* {*********************************************************************

File: calc/calc.cm

  This file shows basic features of the system for evaluation of mathematic
expressions, also referred to as calculator.

Author: Igor Gresovnik, April 1998

************************************************************************}



setfile{outfile calc.ct}  *{ The definition of the result file }

*{
  USEFUL REMARK:
  Values of mathematical expresisons and variables defined in the expression
evaluator can be output by the "write" and "fwrite" functions. If in the
argument block of these functions an expression is written oudside the
quotes in curled brackets immediately following the '$' sign, then the value
of the expression in the moment of execution is output, for example in 
"write{ ${2/3*(a+b)} }". If the '$' sign is folloved by name (space can be
between), then the value of the appropriate variable is output, for example
in "write{ $a1 }" or "write{ $ b }".
}

* {
*************************  FUNCTIONS "=" and "$"  ***************************
  File interpreter knows two basic functions for accessing the calculator:
"=" and "$".
  With "=" command we can assign a value of a mathematic expression to a
variable defined in the calculator. The expression is evaluated at the moment
when the function is called.
  With "$" command we can assign an expression to a variable of the calculator
or define a new calculator function. The expression which is assigned to the
variable is not immediately evaluated at a call to the "$" function.
  Functions has similar syntacs. They require two arguments separated with a
colon. The first one is the name of a variable to which a value or expression
will be assigned and the secnd one is an expression which (or the value of
which in the case of "=") is assigned to a variable. Only "$" can have a
function name at the left side of the colon instead of a variable name. In
this case, function name must be folloved by a list of formal arguments in a
square brackets, separated by commas.
  Any variables or functions which appear in expressions which are arguments
of the calls to "=" or "$", which are not yet defined, are created and defined
after a call to these functions.
  Useful definition: A value of any expression is defined when the values of
any of its subexpressions are defined.
*****************************************************************************
}
write{\n"************  FUNCTIONS = and $  ************"\n\n}
fwrite{\n"************  FUNCTIONS = and $  ************"\n\n}


*{Value of expression is assigned to var. a which is created and set to
that value:}
={a:(3+5)/2} 
write{"Value of variable a: " ${a} \n\n}
fwrite{"Value of variable a: " ${a} \n\n}

*{An expression is assigned to variable c; value of c is not yet defined since
the value of b is not yet defined.}
${c:a+b}

*{In order to define the value of c, we must first assign a value to b.}
={b:3}
write{"a = "$ a", b = "$ b", c = "$ c"."\n}
fwrite{"a = "$ a", b = "$ b", c = "$ c"."\n}

*{We don't need to directly assign a value to b, but can also assign to it an
expression which have a defined value:}
${b:2*a*a}
write{"a = "$ a", b = "$ b", c = "$ c"."\n}
fwrite{"a = "$ a", b = "$ b", c = "$ c"."\n}

*{We can define a new function in the expression evaluator which is then
used as the pre-defined functions:}
${prod[x,y]:x*y}
write{"a = "$ a", b = "$ b", prod[a,b] = "${prod[a,b]}"."\n}
fwrite{"a = "$ a", b = "$ b", prod[a,b] = "${prod[a,b]}"."\n}


* {
**********  CALCULATOR FUNCTIONS VIA INTERPRETER - "definefunctin"  *********
  We can use the file interpreter's capabilities for defining new functions of
the expression evaluator. This is enabled by the function "definefunction". 
The name of a newly defined function must be specified at the beginning of the
argument block in round brackets. Its definition block in square brackets
follows. Each time the newly defined function is evaluated, the definition
block in square brackets is interpreted.
  Two functions of the expression evaluator and one function of the file
interpreter are defined specially for use within the definition block of the
"definefunction" function. The evaluator's function "numargs" returns the
number of arguments which were actually passed to a function defined by
"definefunction". It doesn't require any arguments. Function "argument" returns
a value of a specific argument which was passed to such function. This function
requires one argument which determines which argument of the function defined
by "definefunction" to return (i.e. its successive number). Any number of
arguments can be passed to a function defined by "definefunction", but in the
definition block we specify thet the function reports error if not an
appropriate number of arguments are passed.
  The file interpreter's function return specifies what the function defined
by "definefunction" returns. Its only argument is an expression the value of
which is then returned by the defined function.
*****************************************************************************
}

write{\n "************  FUNCTION definefunction  ************" \n\n}
fwrite{\n "************  FUNCTION definefunction  ************" \n\n}

*{ Example of the definition of an expression evaluator's function using the
file interpreter's capabilities: }

definefunction{ (sumation)
[
  ={i:1} ={ret:0}
  while { (i<=numargs[]) *{ numargs returns the number of actual arguments}
  [
    ={ret:ret+argument[i]} ={i:i+1} *{ argument[i] returns i-th argument }
  ]}
  return {ret}
]}

*{ Test of the newly defined function: }

write{"Test: sumation[6,2,2^3] = " ${sumation[6,2,2^3]} \n\n}
fwrite{"Test: sumation[6,2,2^3] = " ${sumation[6,2,2^3]} \n\n}

*{ Example of the definition of a function which requires exactly two
arguments:}

definefunction{ (sinesum)
[
  *{ This function returns a sine of a sum of the two arguments. }
  if {(numargs[]!=2)
  [
    write{\n "Error: function sinesum requires two arguments, now called with "
           ${numargs[]} "."\n}
    fwrite{\n "Error: function sinesum requires two arguments, now called with "
           ${numargs[]} "."\n}
    return{ 0 }
  ] else
  [
    ={retval:sin[argument[1]+argument[2]]}
    return{ retval }
  ]}
]}

write{"Test: sinesum[6,2,2^3] = " ${sinesum[16,2,2^3]} \n\n}
write{"Test: sinesum[6,2] = " ${sinesum[6,2]} \n\n}
fwrite{"Test: sinesum[6,2] = " ${sinesum[6,2]} \n\n}



* {
**********************  USE OF THE EXPRESSION EVALUATOR  ********************
  The expression evaluator is used in the file interpreter for evaluation of
branching and looping conditions in flow control command like "while" and "if".
This adds a considerable ammount of flexibility to the optimization shell
because the evaluator's pre-built functions can access any piece of the
shell's global data.
  The expression evaluator also contributes flexibility to the use of the
file interpreter's functions. In many functions, their numerical arguments
may be replaced by expressions or expression evaluator's variables.
  Some illustrative examples of use of the expression evaluator are shown
below:
*****************************************************************************
}

write{\n "************  USE OF THE EXPRESSION EVALUATOR: ************" \n\n}
fwrite{\n "************  USE OF THE EXPRESSION EVALUATOR:  ************" \n\n}

*{ Let's define a three dimensional vector variable: }

setvector{v1 3 {1.1 1.2 1.3}}
printvector{v1}
fprintvector{v1}

*{ We can access the values of components of this variable by expression
evaluator's function "getvector". The first argument of this function is
vector name in double quotes and the second one is the required component
number. If this argument is zero then function returns vector dimension: }

={i:1}
while{ (i<=getvector["v1",0])
[
  write{$ i "th component of vector v1 is " ${getvector["v1",i]} "." \n}
  fwrite{$ i "th component of vector v1 is " ${getvector["v1",i]} "." \n}
  ={i:i+1}
]}
write{\n} fwrite{\n}

*{ We can on the other hand use the evaluator with the file interpreter's
functions so that numerical arguments are replaced by expressions which are
evaluated by the evaluator. We have two possibilities: we can write an
expression instead of a number (the expresison must be in curled brackets
immediately following the '$' sign, e.g. "${a+b}") or we can write the
expression evaluator's variable instead of a number (variable name must in
this case follow a '$' sign and a space, e.g. "$ a"). }

setvector { v2 3
  { ${getvector["v1",3]} $ a $ b}
}
printvector{v2}
fprintvector{v2}