ThetaScript Language Reference

From ThetaWiki

Jump to: navigation, search

Contents

ThetaScript

What is ThetaScript

ThetaScript is a procedural programming language.

Its main features are:

  • Backward access to variables
  • Conditional evaluation of statistical properties and
  • Simulated multi-threading

Commands

model

A model is the equivalent of a function or a subroutine. A model is initiated by the keyword model followed by a name and terminated with the keyword end.

A do-nothing model would be formulated as:

model test
end

Importing and exporting variables

Models can import and export values. Imported values are either specified by the user when starting the evaluation of a model, or specified by other models that call this model as a subroutine. Exported parameters must be assigned a value within the body of the model.

Examples of import and export statements:

export y
export a,b,c
export y "A description"
import x
import a,b,c
import x "description"

This is a complete model that imports a variable x and exports the result as variable y:

model example
import x
export y
 
   y = x^2
end

Comments

A comment is initiated with the character % and causes everything after it to be ignored until the end of the line.

Example of a comment:

model commented
% this 
% is 
% a comment
 
end

Assignments

   x = 42
   x = 7 * 9
   y = 2+x

theta

The theta command is a crucial statement in ThetaScript. This command defines the virtual timing model. Every theta statement is followed by a statement defining a time interval. The virtual model time is used to synchronize multiple threads that occur parallel in virtual time. When external numerical routines are called to compute certain model parameters, the timing model also allows synchronization.

This little example assumes that a variable S is provided by a seperate model. The variable x is assigned the value of S at the initial time. After a time step of length one, x assigned the new value of S.

x= S
theta 1
x= S

fork

The previous theta statement requires multiple threads to be executed in parallel. With the fork statement, portions of code are executed in parallel in the timing model. Note that this does not necessarily imply parallel computation on your computing system. A fork block begins with fork and is ended with the end statement. Statements between these two tokens occur in parallel.

The following example shows two fork blocks. The first block forces variable a to zero initially and sets it to 5 at time step 2. The second block proceeds to time 1 and copies the current value of a. After another time step of 2 (at time 3) the value of a is copied again.

fork
   a= 0
   theta 2
   a= 5
end
fork
   theta 1
   x= a     % result: 0
   theta 2
   x= a     % result: 5
end

In case multiple write operations occur in the same timing model, the orignal order of the statements is used. The following example assigns two different values to variable a. A third thread would only sees the value assigned by the second thread.

fork
   theta 1
   a=1
end
fork
   theta 1
   a=a+1
end
theta 1
x=a         % result: 2

if-else-end

Conditional execution is part of every programming language and is part of the ThetaScript syntax.

This example assigns the variable x under certain conditions:

if a>1 | b<10
    x=1
end
if a>1 | b<10
    x=1
else
    x=2
end

loop

The syntax of the loop statement requires a length parameter that must be set at compile time. This parameter may also come from an array variable in which case an iterator must also be defined. This will be shown in the following examples. The loop statement repeats a code block until its corresponding end is reached. The loop length can be specified in two ways.

Fixed loop length

The loop statement can be followed by a number of cycles. The formula is evaluated at the start of the loop. This example cycles though a loop five times. Hence, the final value of x is 10.

x=5
loop x
   x=x+1
end

Infinite loop length

With the number of cycles set to the keyword inf causes the loop to run until all threads with fixed length have finished. This is useful when writing subroutines that compute a time series of arbitrary length or with a lifetime that automatically extends to the length needed.

x=0
loop inf
   x=x+1
   theta 1
end

Array looping

Loops over arrays repeat the loop body once for every component of an array. The loop statement is then followed by a variable that serves as an iterator for each array component, a colon ":" and the array to be processed.

This example cycles over the components of the variable A and squares each of its component.

A= [1,2,3,4]
loop a:A
    a= a^2
end
% result: A=[1,4,9,16]

Multiple array looping

A loop can cycle over multiple arrays simultaneously. Given that two or more arrays are of equal length, an itertator variable can be specified to cycle simultaneously through each array.

The following example cycles though arrays A and B. The variable X is automatically determined to be an array of length 4. Its values are set in the loop body.

A= [1,2,3,4]
B= [1,2,2,2]
loop a,b,x : A,B,X
    x= a+b
end
% result: X=[2,4,5,6]

This loop could equivalently be replaced by the statement X= A+B.

Calling a submodel

Models can be called from the ThetaSuite user interface where the user is prompted for required import parameters, or with a call statement. In the second case, the submodel must be supplied with all parameters the submodel specifies in its import clause. Variables exported by the submodel can optionally be imported by the calling model. All parameters are passed by reference. Hence not only static values but also processes whose values change in time can be passed to submodels.

The following examples shows a call to submodel "sub_model". The first assumes that the submodel imports (reads) the variables a, b and c and exports (returns) variables x and y. Input and returned variables are passed after an import or export statement, respectively. If the variables passed have different names from the submodel arguments, they can be renamed (aliased) by specifing a new name after a to or from statement.

call sub_model
   export a,b
   export a+b to c
   import x,y
   import z from x+y

Example

Assume we now wish to call a "sub_model" from some outside context. The following submodel imports the variable x as a step size, uses it to increase a process with initial value of 0, and returns the result in variable y after every unit and for all units of time.

model sub_model
import x "step size"
export y "result"
 
   y=0
   loop inf
      y=y+x
      theta 1
   end 
end

We can now call this submodel with a step size of 1 by exporting x to it and read back the result in variable y by importing it.

x=1
call sub_model
    export x
    import y
 
% result: y ~ 0 - 1 - 2 - 3 -....

We can also equivalently call the submodel by specifying the initial value of x and reading the result back in variable A as follows:

call sub_model
    export 1 to x
    import A from y
 
% result: A ~ 0 - 1 - 2 - 3 - ....

A third and final example shows the power of using processes instead of values. We can call our submodel once to first create a time-series equal to the either of the previous two examples and thereafter chain this process as an input variable for the step size of a second process.

call sub_model
    export 1 to x
    import y
 
call sub_model
    export y to x
    import A from y
 
% result: A ~ 0 - 1 - 3 - 6 - 10 - 15 - ....

Calling a Matlab function

Any Matlab function can be called by directly typing its function name. Note that only one variable can be returned and all values have to be elements of vectors or matrices.

x = 1
y = atan(x)  
 
% calls MATLAB function "atan"

Note that you can also call user defined m-files: They only have to be located within the Matlab path.

Operators

Backward access

A unique feature of ThetaScript is backward-access to variables. Conventional programming languages can only access a value that was previously assigned to a variable. Since ThetaScript does not evaluate sequentially, future values of variable can also be accessed. The backward access operator is the exclamation mark operator (!). Note that circular definitions are not allowed.

The following example assigns the next value of y to x. Any command that changes the value of y then also sets the value of x.

x = y!     % result: 3
...
y = 3

In some cases, no single instance can be found to determine a backward-referenced variable. The value of the reference is then determined as if the program had been run in reverse command order.

x=y!       % result: 0 if a>1, 2 otherwise
if a>1
   y=0
end
y=2

A special case occurs when a backward-access is conditionally evaluated (if-statements). Backward references only consider assignments after the conditional execution is completed, i.e., after the end-statement. This avoids cyclic definitions of variables in some cases.

x=y!       % result: 0
if y!>1
   y=0
end
y=2

Further properties of the ! operator are as follows:

a!!      ==  a!
(a+b)!   ==  a! + b!
f(a)!    ==  f(a!)
a[i]!    ==  a![i]  (not a![i!])

Array access []

Array elements in ThetaScript can be accessed with C-style brackets after the variable name. Indices however start at 1.

A= [1,2,3,4]
x= A[1]+A[3]

Functions

Stochastic functions

ThetaScript can evaluate conditional statistical properties of variables. The results are conditional on all parameters that are known at the corresponding model time. The arguments of stochastic functions are assumed to have access values backwardly, i.e., to have access to future assignments.

E

The function E computes the conditional expected value of a variable or an expression.

This example computes the variable x as the expected value of S*EUR at time 10 conditioned on all information that is known at time 5.

theta 5
x= E(y)
theta 5
y= S * EUR

Beta

The Beta function takes two arguments and computes the beta factor between these two values. The first argument can have multiple dimensions in which case the Beta function computes a beta factor for each component of that array. See Hedging in ThetaScript for applications.

Other functions

length

The length of array can be determined with the length function.

A= [1,1,1,1]
l= length(A) % result: 4

System parameters

System parameters are compile-time parameters that can be extracted with an ampersand (@) followed by one of the following keywords.

@time

This variable accesses the current model time. It is the sum of all theta time steps.

@dt

The time interval parameter @dt has different values depending on its context. If @dt is found within the argument of the command theta, it evaluates to the time interval of the next time step. In case @dt is located elsewhere, it evaluates to the time elapsed since the thread's previous invocation of the theta command.

This example computes Brownian motion for all time steps needed for a simulation since @dt is an argument to theta.

model BrownianMotion
export W "Browion process"
 
   W=0
   loop inf
       theta @dt
       W= W + sqrt(@dt) * randn()
   end
end

Matlab Backend

Models defined in ThetaScript can call Matlab processes via the Theta command. It returns a state variable that contains fields readable by the ThetaScript model. Note that Matlab cannot read variables defined in ThetaScript.

The communication with the Theta command has two distinct phases. First, there is an initialization phase where the Theta command is called without arguments and returns the state variables intialized. Thereafter, the Theta process uses Matlab functions to propagate the state for a timestep dt. Thus it is only possible to define Markov processes albeit with an arbitrary state space.

The descriptor returned by the Theta command must be a structure with entries for each variable. Each entry is itself another structure that must contain the following fields:

  • comment: A short decription
  • value: An initial value
  • dim: The array dimension for the initial value, if not provided defaults to 1
function state = Theta(dt, state)
 
  if nargin == 0
    state.S.comment = 'Stock price';
    state.S.value= 100;
    state.EUR.comment = 'Numeraire';
    state.EUR.value= 1;
  else
    r = 0.05;
    mu = r;
    sigma = 0.4;
    state.S   = state.S .* exp( (mu-0.5*sigma^2)*dt + sqrt(dt)*sigma*randn(size(state.S)));
    state.EUR = state.EUR* exp(-r*dt);
  end
end
Personal tools