Portable TROLL is an interactive computer software package designed for econometric modelling and other applications of statistical analysis and mathematical simulation. Because of its emphasis on time series, TROLL is particularly well-suited to the study of processes that take place in calendar time. What sets it apart from other econometric and statistical packages is its unparalleled ability to simulate quickly the dynamic behavior of large, complex, non-linear systems involving forward-looking behavior. TROLL's salient features include an algebraic modelling language for flexible and precise specification of model structure; a programming language for automation of complex tasks; a database engine for efficient storage and retrieval of time series data; two hundred algebraic, statistical, and trigonometric functions for transformation and manipulation of data; and over a hundred ready-to-use commands for statistical data analysis and model simulation. TROLL is designed both to interact easily with users and to operate on pre-written command files without user attention. Both non-technical users and experienced programmers have a place in the world of Portable TROLL.
Although TROLL now comes on a compact disc and downloads over high-speed internet connections, its history goes back to the days of punch cards and paper tape. During the 1960's, Massachusetts Institute of Technology (MIT) economist Edwin Kuh spearheaded a successful effort to develop a "Time-shared Reactive On-Line Laboratory" -- a system of computer software that would let economists develop and test mathematical models without having to concern themselves with all the programming details. The first "TROLL" (now called "Mainframe TROLL" to distinguish it from today's portable version) was released in 1971.
Since then TROLL has remained a critical tool for large-scale econometric modelling because its development process has responded directly to the needs and interests of people in the field. In addition to satisfying the requirements of practicing econometric modellers, Mainframe TROLL was a testing ground for the introduction of new algorithms and techniques such as Kuh-Neese-Hollinger structural sensitivity analysis. In 1987, MIT licensed to Intex Solutions, Inc. the exclusive right to develop and market TROLL. In 1991, with the support from the Bank of Canada, the Federal Reserve Board of Governors, the International Monetary Fund, the Bank of Norway, and the Commission of the European Community, Intex began the creation of Portable TROLL. Portable TROLL now offers the major capabilities of Mainframe TROLL while eliminating restrictions on size of models and portability across platforms.
The designers of Portable TROLL had four objectives in mind: power, portability, extensibility, and compatibility with the existing mainframe product. All four of these objectives are relevant to today's TROLL user. Power -- Portable TROLL's unlimited capacity, unmatched performance, and ever-improving analytic capability -- probably represents the primary reason that users choose TROLL. Portability means that TROLL source code written for one platform will run on any platform. Thus PC users and UNIX Workstation users can share TROLL programs without difficulty. Since Portable TROLL itself is written in platform-independent code, users need not fear obsolescence: any future platform that supports the standard "C" programming language will support TROLL. Extensibility allows users to tailor TROLL to their own needs, and since users often make their extensions available to one another, TROLL's capabilities promise to grow in ways that can immediately reflect the needs of users. Finally, backward compatibility, in addition to the obvious advantage for former Mainframe TROLL users, provides new users with access to applications developed over TROLL's history by such organizations as the International Monetary Fund.
Broadly, Portable TROLL's capabilities can be divided into "analysis" and "management." "Analysis" -- calculation, estimation, and simulation -- produces tangible results, but "management" -- data processing, model specification, and system maintenance -- provides the underpinnings for those results. Although TROLL's analytical capabilities are its most prized features, an understanding of TROLL's management capabilities is more fundamental to its successful use.
This Guide is intended as both a learning tool for beginning users and a "functional" reference for more advanced users. If you are just starting to learn TROLL, you can read the chapters one by one to get a gradual introduction to Portable TROLL's various capabilities. If you have been working with TROLL for a while but need information about how to accomplish certain kinds of tasks (or if you are simply too impatient to read anything cover-to-cover), you can skip around or go directly to the relevant sections.
Unlike the Portable TROLL Reference Manual and the Portable TROLL Programming Language manual, this volume is organized in terms of what you want to do rather than how you do it. Thus, for example, if you want to find out how to import data into Portable TROLL, you can go to the chapter on "Using and Managing Data" in this volume. On the other hand, if you want more detailed information on how to use a particular command such as "SEARCH," you can go to the relevant section in the Reference Manual.
The specifics of how you begin a TROLL session will depend on your host environment and, in some cases, on the details of your TROLL installation. If the procedures described here do not work for you, contact your local TROLL administrator or systems consultant.
Most likely, you work in either a UNIX environment or Windows environment. Under most UNIX installations, you can invoke TROLL by typing "troll" (normally lower case) at a command prompt. In some cases, it will first be necessary to find the directory in which TROLL is installed and create a link to the TROLL executable.
In a Windows environment, there are several ways to run TROLL. In a command prompt session (or MS-DOS session), you can type "troll" (upper or lower case) at the command prompt. (This assumes you have the TROLL directory on your "path" list, which will be the case for a standard installation.) Similarly, you can use the Windows "Run" command from the Start menu (or the "File" menu in Windows 3.1): choose "Run," type "troll" in the "Open:" box, and choose "OK". These methods invoke the "console" version of TROLL, which is the same as the UNIX version in most respects.
Alternatively, if you are working in a Windows environment and you have the GUI version of TROLL, you can choose "TROLL for Windows" from the "Programs" menu or double-click on the Desktop shortcut for TROLL (if one exists). If you invoke TROLL this way, you will see a Startup dialog box. Unless you want to change the TROLL session parameters, you can simply choose "OK" (or press "Enter"). This will invoke the GUI (Graphical User Interface) version of TROLL, which includes a separate "Input" window for entering TROLL commands. The GUI is covered in more detail in Appendix A. Since not all users have the GUI available, the rest of this User's Guide is written with reference to the console version. For the most part, everything in here applies to the GUI version as well, except that you type commands into the "Input" window. The appearance of the "Session" window will be essentially the same as that of the command window in the console version.
When you invoke TROLL, it will begin by prompting you for a TROLL Command. The beginning of the session should look something like this:
TROLL Release 1.033 Copyright (C) Intex Solutions, Inc. 1993-1997 Copyright (C) Massachusetts Institute of Technology 1978-1987 TROLL Command:
The first thing to know about TROLL commands is that each command should end with a semicolon. For example, type "DO;" at the command prompt. TROLL should respond with another command prompt, indicating that it has understood and processed your request and is ready for the next command. In this case, you have told TROLL to "do" nothing, and it has graciously obliged.
Now try typing "DO" without the semicolon. The result should look something like this:
TROLL Command: do Equation or ';':
This time you have told TROLL to "do" something, but it doesn't know what, so instead of processing your command, it asks for more information. If you type a semicolon now, TROLL will respond with another command prompt, indicating again that it has succeeded in doing nothing. Alternatively, you could ask TROLL to do something -- in particular, to evaluate an expression. For example, when TROLL asks for "Equation or ';'", try typing "X=5;". TROLL will respond with another command prompt, as follows:
TROLL Command: do Equation or ';': x=5; TROLL Command:
In this case, TROLL has evaluated the expression "5" and assigned the value of that expression to the variable "x". You can verify this with another DO command using the PRTDATA function, as follows:
TROLL Command: do Equation or ';': prtdata(x); X: Numeric scalar: 5 TROLL Command:
The command "do prtdata(x);" asks TROLL to evaluate the expression "prtdata(x)". Here the "value" of the expression is really not very important. Instead, the PRTDATA function is useful for its "side effect": when TROLL evaluates the PRTDATA function, it prints the value of the argument (in this case, x) on the computer screen (normally).
The PRTDATA function can be abbreviated as "PRT.", as in the following:.
TROLL Command: do prt.(x); X: Numeric scalar: 5 TROLL Command:
In TROLL, as in ordinary English, the dot is often used to represent an abbreviation.
If you're just learning to use TROLL, one of the first things you may want to learn is how to get information about your TROLL session. TROLL gives the user such information in response to "look" commands, which normally begin with "LK". For example, try typing "LKACCESS;" in response to the "TROLL Command:" prompt. The result should look something like this:
TROLL Command: lkaccess; Accessed Databases: Alias DB Type R/W? Filetype Basic? ID ----- ------- ---- -------- ------ ----- SAVE MEMDB R/W DATA Fixed (none) . DISK R/W ALL Fixed (none) TROLLSYS DISK R ALL Fixed y:\troll TROLL Command:
The LKACCESS command gives fundamental information about a TROLL session, and it also demonstrates a major feature of TROLL: TROLL can access multiple databases at once. For example, you could have a variable called X in the "SAVE" database and a variable called Y in the "." (dot) database, and you could add the two with a statement like, "DO Z=X+Y;" without telling TROLL which database contains which variable. (You would have to tell TROLL where to search for variables.)
LKACCESS reports the databases that are directly available to the TROLL session right now. The first column, "Alias," gives the name used for the database within the TROLL session. The last column, "ID," gives the more general name for the database. The other columns give information about the characteristics of the database and its relationship to the TROLL session. The third column, for instance, tells whether this TROLL session has read ("R") or write ("W") access to the database. The fourth column tells the "Filetype" of the database, which determines the kind of information (programs, models, data, etc.) it can contain.
The second column gives the "database type", which determines the format and other characteristics of the database. In this example, only the types MEMDB and DISK appear. A MEMDB is a temporary database that resides temporarily in the computer's memory and will disappear at the end of the TROLL session. A DISK database normally corresponds to a "directory" in the host computer file system, and its contents will normally remain until deleted explicitly.
TROLL also offers several other database types (mostly "permanent" databases that correspond to "files" in the host system. The specific types available will depend on your installation. You can display the available database types with the command LKDBTYPE, as follows:
TROLL Command: lkdbtype;
Available Database Types:
DISK
TROLLDB
MEMDB
FORMDATA
FORMOLD
TESTBIN1
TSD
"TROLLDB" and "FORMDATA" are among the most commonly used database types. Both FORMDATA and TROLLDB databases normally correspond to host system files. TROLLDB databases use a binary (computer-readable numeric) format that enables TROLL to access them efficiently; FORMDATA databases use an ASCII (text) format that enables human beings to read them.
Other look commands that you can use generally in TROLL include LKOUTOPT, which shows output options in effect (see...); LKCONOPT, which shows convergence criteria and other convergence-related options (see...); LKSTATUS, which shows information about the model and time-series context (see...); LKSYSOPT, which shows the system options (such as log files) that are in effect (see...); LKSEARCH, which shows the order of database use (explained in the following section). There are also many look commands that apply in specific contexts, such as modelling (LKORD, LKSYM, LKXREF, see...), seasonal adjustment (LKSEASOPT, see...), estimation (LKBOUNDS, LKDLAG, LKPREG, LKREGOPT, LKNLSOPT, LKFILMLAG, LKITERANGE, LKOUTLVL, see...), and simulation (LKDATES, LKDROP, LKITERS, LKLIST, LKSIMALG, LKSIMPER, LKVAL, see...).
Besides knowing how to look for information from TROLL, it's important to know how TROLL looks for information in databases. The following section discusses this topic.
TROLL's ability to access multiple databases at once raises some important problems. For example, what happens when a variable with the same name is in two different databases? When you refer to one of those variables by name, how does TROLL know which one you are talking about? Also, if TROLL is accessing many large databases at once, how can it manage the potentially cumbersome computer resources efficiently?
The answer to these questions is in something called a "search list," an ordered list of databases used in a TROLL session. TROLL's search list tells it where to look for variables, and in what order to look in different databases. Only accessed databases can be on the search list. An accessed database may or may not be on the search list. Until an accessed database appears on the search list, TROLL will ignore it.
You can view the current search list with the LKSEARCH command, as in this example:
TROLL Command: lksearch; Current SEARCH list: Name W? Filetype Basic? ---- -- -------- ------ SAVE W DATA BASIC . W NONDATA BASIC TROLLSYS NONDATA BASIC
The "Name" column lists the databases, in search order, by their aliases. The "W?" column specifies whether a database is searched for writing ("W") or only for reading (" ") information. Note that a database can be "accessed" with write access but still appear on the search list without a "W": TROLL will not write to such a database unless the search list changes. The "Filetype" tells what type of information TROLL will seek in the database. For example, a "DATA" file will be searched only for data, not for programs or models. The "Basic?" column refers the status of a file's presence on the search list. ("BASIC" files are protected from being removed without an explicit command.)
The search list is a critical element in TROLL's architecture. It allows TROLL to avoid ambiguity in names, and it enables TROLL to use resources efficiently, since TROLL can stop searching as soon as it finds a name in one of the databases on the list. For information that is conveniently available in databases near the top of the list, TROLL can avoid a potentially costly search among less easily accessible databases. The ability to make a database read-searchable but not write-searchable prevents fundamental data from being overwritten.
The search list also creates potential pitfalls for users. If you have variables (or programs or models) with the same name in more than one database, you have to be careful to avoid using the wrong one. If two variables with the same name refer to the same information but reside in different databases, you have to be careful to update both when the information changes. If you intend to update information from within a TROLL session, you have to make sure the database containing that information is write-searchable.
You can control TROLL's database access and search lists by using the commands ACESSS, SEARCH, DELACCESS, and DELSEARCH. The ACCESS command makes a database available to TROLL, so that the database will appear on the "access list" reported by LKACCESS. The SEARCH command adds a database to a the search list and allows the user to specify its position on the list. ACCESS and SEARCH are perhaps the most important commands for managing data in TROLL. DELACCESS and DELSEARCH are used to remove databases from the access and search lists.
The following is a simple syntax for the ACCESS command:
access alias type dbtype id idname <mode modeval>;
(The full syntax is described in the Reference Manual.)
The "alias" is the name to be used for the database within the TROLL session. The "idname" is a name by which TROLL can identify the database initially in order to gain access. Often a host system filename is used as the "idname."
Suppose you want to use some information in a database that resides in a file called "usanipa.frm". (The ".frm" extension indicates that this refers to a "formdata" database -- a text file in a format that TROLL recognizes.) If you only want to use the information, not revise it or supplement it, then the safer option is to access it in read-only mode. This happens to be the default, so you can omit the <mode modeval>. The following example assumes the file is located in the main directory of a PC host system. (The "idname" would be slightly different on a Unix system.) This command gives TROLL access to usanipa.frm, using the alias "nipa":
TROLL Command: access nipa type formdata id c:\usanipa.frm;
LKACCESS can verify that the database is now available to TROLL:
TROLL Command: lkaccess; Accessed Databases: Alias DB Type R/W? Filetype Basic? ID ----- ------- ---- -------- ------ ----- SAVE MEMDB R/W DATA Fixed (none) . DISK R/W ALL Fixed (none) TROLLSYS DISK R ALL Fixed y:\troll NIPA FORMDATA R DATA c:\usanipa.frm
Although the database is now available, TROLL will ignore it until it appears on the search list. To put it on the search list, you could use the following SEARCH command:
TROLL Command: search nipa;
...and verify with LKSEARCH:
TROLL Command: lksearch; Current SEARCH list: Name W? Filetype Basic? ---- -- -------- ------ SAVE W DATA BASIC . W NONDATA BASIC TROLLSYS NONDATA BASIC NIPA DATA
As per its default, SEARCH has put the new database at the bottom of the search list. Thus a variable in the "NIPA" database will only be used if a variable of the same name does not appear in the "SAVE" database. Suppose, alternatively, that you're not sure what's in the "SAVE" database, and you want to make sure that TROLL uses the data from the "NIPA" database. You could do that as follows:
TROLL Command: delsearch nipa; TROLL Command: search first nipa; TROLL Command: lksearch; Current SEARCH list: Name W? Filetype Basic? ---- -- -------- ------ NIPA DATA SAVE W DATA BASIC . W NONDATA BASIC TROLLSYS NONDATA BASIC
The initial DELSEARCH command removes "NIPA" from the search list. The subsequent SEARCH command puts "NIPA" back on the search list, this time at the top.
There is much more you can do with ACCESS and SEARCH than what we have seen so far. A deeper discussion appears at the beginning of the chapter 3 on "Using and Managing Data." Using and managing data, strictly speaking, is only one of several uses for TROLL's database access methods; ACCESS and SEARCH are also important in managing models and programs. You will see references to these commands throughout this Guide.
Before considering more of the preliminaries, and before examining the special capabilities of TROLL, let's look at a very simple example of TROLL's basic functionality: good, old-fashioned linear regression. We'll use the USANIPA.FRM file from the previous section. In this example, we assume again that the file resides in the main directory of a PC-type host system, and we also assume that its contents include annual data for U.S. gross domestic product ("GDP") and personal consumption expenditures ("CONS") from 1969 through 1995. First, set up the ACCESS and SEARCH environment as above. Then type, "OLS CONS GDP, 1969A to 1995A;" at the command prompt. (The "A" after 1969 and 1995 stands for "annual," which identifies 1969 and 1995 as years rather than ordinary numbers.)
TROLL Command: access nipa type formdata id c:\usanipa.frm; TROLL Command: search nipa; TROLL Command: ols cons gdp, 1969a to 1995a; ORDINARY LEAST SQUARES LHS VARIABLE: CONS NOB = 27 NOVAR = 2 NCOEF = 2 RANGE: 1969A to 1995A RSQ = 0.9964 CRSQ = 0.996256 F(1/25) = 6919.221076 PROB>F = 0 SER = 38.738866 SSR = 37517.492707 DW(0) = 1.19302 COND = 10.012457 MAX:HAT = 0.151311 RSTUDENT = -2.214826 DFFITS = -0.459821 COEF ESTIMATE STER TSTAT PROB>|T| GDP 0.743172 0.008934 83.181855 0 CONST -425.007001 37.695226 -11.274823 0 OLS Command:
If you've done this sort of thing before, this result should look reasonably familiar. At the top, it identifies the procedure as "Ordinary Least Squares" and the Left-hand-side variable as "CONS." It then presents various regression statistics, and finally it shows the coefficient estimates, along with their standard errors, T-statistics, and probability levels. In this case the probability levels are too small to express in the available decimal places for this format, so they are reported as zero. (In other words, for practical purposes, these results could not have appeared by chance if the true coefficients were zero.)
You may notice the absence of a "TROLL Command" prompt after the OLS results. Instead, there is a new prompt, "OLS Command." When you typed the command beginning with "ols cons..," TROLL launched a new "task" called "OLS." That task will remain in control until you end it. While the OLS task is in control, you have available various commands that apply specifically to that task. One example is regression diagnostics, requested by the command "PRTDIAG". Let's request a set of studentized residuals for the above regression:
OLS Command: prtdiag rstudent;
RSTUDENT
1969A -0.875778
1970A 0.7522
1971A 0.28213
1972A -0.278093
1973A -1.519414
1974A -1.040353
1975A 1.444587
1976A 0.612251
1977A -0.542679
1978A -1.832535
1979A -2.214826
1980A 0.425991
1981A -0.296821
1982A 1.731931
1983A 2.183125
1984A 0.257016
1985A 0.667252
1986A 1.058604
1987A 0.853092
1988A 0.605524
1989A -0.633409
1990A -0.329186
1991A 0.075551
1992A -0.196292
1993A 0.145207
1994A -0.781143
1995A -0.685686
OLS Command:
Those residuals look reasonable. Let's get out of the OLS task now:
OLS Command: quit; TROLL Command:
Just to see how the task level differs from TROLL level, try typing "PRTDIAG RSTUDENT" again.
TROLL Command: prtdiag rstudent; ERROR 101 Not a command: PRTDIAG TROLL Command:
Oops! TROLL has never heard of "PRTDIAG." At the TROLL level, regression diagnostics don't exist. TROLL wouldn't even know which regression you were talking about. Of course, there are ways to save various regression information before leaving the OLS task, but once you leave OLS, you must access that information through TROLL's "high-level" access methods, not through regression-specific commands.
As always, there are exceptions. Some of the information that you gave the OLS task actually becomes a global setting of the TROLL environment, and thus it is still available, even without being saved explicitly. In particular, the time range ("bounds") of the regression, which you set when you started OLS, remains valid. You can examine the currently active time range by typing "LKBOUNDS":
TROLL Command: lkbounds;
***** Regression Bounds *****
Time bounds
# of observations :: 27 # of intervals :: 1
1: 1969A to 1995A
TROLL Command:
Having examined some of TROLL's basic functionality, let's take a step back and look more broadly at TROLL's capabilities. If you're a new user, many of the TROLL sessions shown here may appear cryptic. Don't worry about understanding the details of the syntax and methods. The purpose of this section is just to give you an idea of what is possible, so you can get an idea of how you might use TROLL and begin to get a feeling for the way TROLL looks and works.
TROLL has approximately 200 built-in functions to perform jobs relating to a wide range of activities, including data generation, trigonometry, matrix algebra, input/output, probability distributions, statistical analysis, model manipulation, missing values, dating of time series, and programming...to name a few. Here are some examples:
If you read the section in this chapter on "Entering Troll Commands", you have already seen an output function in action: "PRTDATA", or "PRT.", as it is affectionately known. For a user's guide, this kind of output is critical, because it puts data where users can see it. You will see plenty of examples of PRTDATA (or "PRT.") throughout this book. For now, some brief examples of what PRTDATA does: it simply displays the values of its arguments on the computer screen, as follows:
TROLL Command: do prtdata(5); 5: Numeric scalar: 5 TROLL Command: do prt.(5); 5: Numeric scalar: 5 TROLL Command: do prtdata(5*2); 5*2: Numeric scalar: 10 TROLL Command: do prt.(5*2,2*3); 5*2: Numeric scalar: 10 2*3: Numeric scalar: 6
Naturally, PRT. can do more than just print scalars. (The following example assumes that the NIPA database, with the variable GDP, is still on your search list.)
TROLL Command: do prt.(gdp);
GDP:
GDP = GDP
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 2914.78093 2915.69401 2998.88658 3152.28521
1973A : 3316.13414 3295.33595 3268.55204 3429.96575
1977A : 3584.68329 3757.35818 3852.01535 3831.26806
1981A : 3925.14073 3840.98742 3995.87775 4268.50453
1985A : 4427.40332 4560.65358 4692.32470 4870.55919
1989A : 5034.52514 5099.61333 5049.97731 5187.46398
1993A : 5305.36592 5490.10025 5601.5644
The rest of the examples in this section will make liberal use of "PRT.", usually with one or more functions nested as its argument (or arguments), in order to demonstrate the effects of those functions.
Anything a typical hand-held calculator can do, TROLL can do better (or at least equally well):
TROLL Command: do prt.(sqrt(1000)); SQRT(1000): Numeric scalar: 31.622777 TROLL Command: do prt.(arcsin(1)); ARCSIN(1): Numeric scalar: 1.570796 TROLL Command: do prt.(absv(2*(3-5))); ABSV(2*(3-5)): Numeric scalar: 4
Any of these functions could also take a matrix or timeseries as the argument, and TROLL would apply the function separately to each element of the matrix or timeseries. For example, you might want to transform GDP into something less scale-sensitive, such as its natural logarithm:
TROLL Command: do prt.(log(gdp));
LOG(GDP):
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 7.97755 7.97786 8.00599 8.05588
1973A : 8.10655 8.10026 8.09210 8.14030
1977A : 8.18442 8.23147 8.25635 8.25095
1981A : 8.27515 8.25348 8.29301 8.35901
1985A : 8.39556 8.42522 8.45368 8.49096
1989A : 8.52407 8.53692 8.52713 8.554
1993A : 8.57647 8.61070 8.63080
Many TROLL functions apply to a whole matrix or timeseries, rather than to individual elements. TROLL has plenty of statistical functions that fit that description:
TROLL Command: do prt.(median(gdp));
MEDIAN(GDP):
Numeric scalar: 3925.140736
TROLL Command: do prt.(range(gdp));
RANGE(GDP):
Numeric array --
1 space dimension: 2
Space dimension number 1 -->
[1]: 2914.780935 5601.5644
Note that RANGE, like many functions, returns a vector -- in this case the minimum and maximum values of the time series. If you are a beginning user, this may be the first time you have seen the phrase "space dimension" in a TROLL output. In TROLL, vectors and matrices have "space dimensions," whereas time series have "time dimensions," and a time series of vectors or matrices will have both space and time dimensions.
Some statistical functions in TROLL do more than just return values, for example:
TROLL Command: do prt.(stats(gdp));
GDP:
NVals: 27 Mean: 4135.815598
Min: 2914.780935 Max: 5601.5644
Standard Deviation: 850.353715
STATS(GDP):
Numeric array --
2 space dimensions: 1 by 5
Space dimension number 2 -->
[1,1]: 27 4135.815598 2914.780935 5601.5644
[1,5]: 850.353715
The STATS function begins its work by printing out a set of summary statistics. It then places those summary statistics in an array to return to the calling program. In this case, "PRT." was the calling program, so PRT. takes that array and displays it on the screen. This array is actually a row vector -- or a matrix with a single row and multiple columns. By convention, the row number of a matrix is specified before the column number. Since the matrix output by STATS has one row and five columns, TROLL reports it to have "2 space dimensions," of which the first is "1."
You might also be interested in the relationship between two time series:
TROLL Command: do prt.(correl(gdp,cons));
CORREL(GDP,CONS):
Numeric array --
2 space dimensions: 2 by 2
Space dimension number 2 -->
[1,1]: 1 0.998198
[2,1]: 0.998198 1
And if the time series aren't yet in the form you want them, you can convert them on-the-fly:
TROLL Command: do prt.(covar(log(gdp),log(cons)));
COVAR(LOG(GDP),LOG(CONS)):
Numeric array --
2 space dimensions: 2 by 2
Space dimension number 2 -->
[1,1]: 0.04296 0.050339
[2,1]: 0.050339 0.05927
You've seen several simple examples of TROLL matrices. Now let's look at some of the things TROLL can do with them. Suppose you want your statistics as a column vector instead of a row vector. Just transpose them:
TROLL Command: do statvec=transp(stats(gdp));
GDP:
NVals: 27 Mean: 4135.815598
Min: 2914.780935 Max: 5601.5644
Standard Deviation: 850.353715
TROLL Command: do prt.(statvec);
STATVEC:
STATVEC = TRANSP(STATS(GDP))
Numeric array --
1 space dimension: 5
Space dimension number 1 -->
[1]: 27 4135.815598 2914.780935 5601.5644
[5]: 850.353715
The 1x5 matrix (row vector) produced by the STATS function is now a 5x1 matrix (column vector), which -- in TROLL's world -- is equivalent to an ordinary one-dimensional array. The "two-dimensional" array is now a "one-dimensional" array. Where did the other dimension go? In a sense, it still exists, but TROLL no longer cares about it. Every TROLL matrix contains an infinite number of "trailing dimensions" -- space dimensions of size 1 that are ignored unless they are needed. Consider the following:
TROLL Command: do prt.(transp(statvec));
TRANSP(STATVEC):
Numeric array --
2 space dimensions: 1 by 5
Space dimension number 2 -->
[1,1]: 27 4135.815598 2914.780935 5601.5644
[1,5]: 850.353715
The second dimension has appeared again. To perform transposition, TROLL needs two dimensions, and it calls the "trailing" second dimension out of hiding. TROLL also has a function to give the size of a specified dimension, as follows:
TROLL Command: do prt.(dimsize(statvec,1)); DIMSIZE(STATVEC,1): Numeric scalar: 5
The first dimension of STATVEC is size 5: five rows.
TROLL Command: do prt.(dimsize(statvec,2)); DIMSIZE(STATVEC,2): Numeric scalar: 1
As you can see, STATVEC does have a second dimension -- of size 1: one column, if you like. By the way, STATVEC also has a third dimension:
TROLL Command: do prt.(dimsize(statvec,3)); DIMSIZE(STATVEC,3): Numeric scalar: 1
In fact, it has millions of dimensions:
TROLL Command: do prt.(dimsize(statvec,1000000)); DIMSIZE(STATVEC,1000000): Numeric scalar: 1
Even if you never need to use anything beyond the 999,999th dimension, it's nice to know the rest are there waiting.
On the other hand, you may want to know how many "active" (non-trailing) dimensions a matrix has. Use the NDIMS function:
TROLL Command: do prt.(ndims(statvec)); NDIMS(STATVEC): Numeric scalar: 1
Or you may just want to know how many elements it has:
TROLL Command: do prt.(nvals(statvec)); NVALS(STATVEC): Numeric scalar: 5
TROLL can do quite a lot with arrays and matrices, so just a few exotic examples here. Maybe you want to reverse the order of an array and paste it against itself lengthwise to make a two-dimensional matrix. You can do that with the TROLL functions REVERSE and PARTCOMB (combine partitions):
TROLL Command: do sillymat=partcomb(1,2,statvec,reverse(statvec));
TROLL Command: do prt.(sillymat);
SILLYMAT:
SILLYMAT = PARTCOMB(1,2,STATVEC,REVERSE(STATVEC))
Numeric array --
2 space dimensions: 5 by 2
Space dimension number 2 -->
[1,1]: 27 850.353715
[2,1]: 4135.815598 5601.5644
[3,1]: 2914.780935 2914.780935
[4,1]: 5601.5644 4135.815598
[5,1]: 850.353715 27
And if you don't happen to like row 4, get rid of it:
TROLL Command: do prt.(delrow(sillymat,4));
DELROW(SILLYMAT,4):
Numeric array --
2 space dimensions: 4 by 2
Space dimension number 2 -->
[1,1]: 27 850.353715
[2,1]: 4135.815598 5601.5644
[3,1]: 2914.780935 2914.780935
[4,1]: 850.353715 27
...or replace it:
TROLL Command: do prt.(setrep(sillymat,0,4,col(sillymat)));
SETREP(SILLYMAT,0,4,COL(SILLYMAT)):
Numeric array --
2 space dimensions: 5 by 2
Space dimension number 2 -->
[1,1]: 27 850.353715
[2,1]: 4135.815598 5601.5644
[3,1]: 2914.780935 2914.780935
[4,1]: 0 0
[5,1]: 850.353715 27
And of course TROLL can do ordinary matrix algebra. TROLL takes advantage of the associative property of matrix multiplication, so that you can multiply an arbitrarily long series of matrices (provided they are conformable):
TROLL Command: do x=transp(statvec); TROLL Command: do prt.(matmult(x,sillymat,1/range(gdp))); MATMULT(X,SILLYMAT,1/RANGE(GDP)): Numeric scalar: 29592.974078
Yes, TROLL does derivatives:
TROLL Command: do deriv(2*x,x); DERIV(2*X,X) = 2
...and partial derivatives:
TROLL Command: do deriv(cos(y)*log(x*y),y); DERIV(COS(Y)*LOG(X*Y),Y) = -(SIN(Y))*LOG(X*Y)+COS(Y)*X/(X*Y)
...and second derivatives:
TROLL Command: do deriv(log(x+y),x,x); DERIV(LOG(X+Y),X,X) = -(1/(X+Y))/(X+Y)
...and cross-derivatives:
TROLL Command: do deriv(5*x**2*y,x,y); DERIV(5*X**2*Y,X,Y) = 5*2*X
...and (in case anyone's interested) tenth derivatives:
TROLL Command: do deriv(x**12,x,x,x,x,x,x,x,x,x,x); DERIV(X**12,X,X,X,X,X,X,X,X,X,X) = 12*11*10*9*8*7*6*5*4*3*X**2
If you'd rather know the values of the derivative at specific points, TROLL can do that too:
TROLL Command: do prt.(deriv("eval",log(cons/gdp),gdp));
DERIV(LOG(CONS/GDP)
DERIV(LOG(CONS/GDP),GDP) = -(CONS/GDP)/GDP/(CONS/GDP)
DERIV("eval",LOG(CONS/GDP),GDP):
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : -0.000343 -0.000343 -0.000333 -0.000317
1973A : -0.000302 -0.000303 -0.000306 -0.000292
1977A : -0.000279 -0.000266 -0.00026 -0.000261
1981A : -0.000255 -0.00026 -0.00025 -0.000234
1985A : -0.000226 -0.000219 -0.000213 -0.000205
1989A : -0.000199 -0.000196 -0.000198 -0.000193
1993A : -0.000188 -0.000182 -0.000179
To see how TROLL can handle character strings, lets redo the last example in two parts. First, take a symbolic derivative:
TROLL Command: do symderiv=deriv("noprint",log(cons/gdp),gdp);
TROLL Command: do prt.(symderiv);
SYMDERIV:
String scalar: "-(CONS/GDP)/GDP/(CONS/GDP)"
Now, evaluate that derivative:
TROLL Command: do prt.(evalstr(symderiv)); EVALSTR(SYMDERIV): Numeric scalar timeseries -- Time dimension: Periodicity 1, 1969A to 1995A (27 observations) Time dimension --> 1969A : -0.000343 -0.000343 -0.000333 -0.000317 1973A : -0.000302 -0.000303 -0.000306 -0.000292 1977A : -0.000279 -0.000266 -0.00026 -0.000261 1981A : -0.000255 -0.00026 -0.00025 -0.000234 1985A : -0.000226 -0.000219 -0.000213 -0.000205 1989A : -0.000199 -0.000196 -0.000198 -0.000193 1993A : -0.000188 -0.000182 -0.000179
The argument to the EVALSTR function is a string containing (usually) an arithmetic expression. EVALSTR evaluates that expression and returns the value. In this case the argument contains the names of time series, so EVALSTR performs its evaluation for each observation in those time series.
There are plenty of things you can do with strings besides evaluating them. For example, suppose you're interested in disposable income ("YD") instead of gross domestic product ("GDP"). Using the CHANGESTR function, you can perform a string replacement in the (previously formed) SYMDERIV expression:
TROLL Command: do prt.(changestr(symderiv,"GDP","YD")); CHANGESTR(SYMDERIV,"GDP","YD"): String scalar: "-(CONS/YD)/YD/(CONS/YD)"
Then, if you want, you can evaluate the string again.
You can form an array of strings using COMBINE (which works for numerical data as well):
TROLL Command: do couple=combine("MAN", "AND", "WIFE");
TROLL Command: do prt.(couple);
COUPLE:
COUPLE = COMBINE("MAN","AND","WIFE")
String array --
1 space dimension: 3
Space dimension number 1 -->
[1]: "MAN" "AND" "WIFE"
Once you have an array of strings, you can join the elements together, and even place a specified separator between them, using JOINSTR:
TROLL Command: do prt.(joinstr(couple," ")); JOINSTR(COUPLE," "): String scalar: "MAN AND WIFE"
What TROLL hath joined, TROLL can also put asunder, using the TOKENIZE function, which separates a string into individual syntactical elements:
TROLL Command: do prt.(tokenize(joinstr(couple," ")));
TOKENIZE(JOINSTR(COUPLE," ")):
String array --
1 space dimension: 3
Space dimension number 1 -->
[1]: "MAN" "AND" "WIFE"
You can change case; you can repeat a string an arbitrary number of times; and so on; as in the following command:
TROLL Command: do prt.(repstr(upper(changestr("go? ","?","!")),3));
REPSTR(UPPER(CHANGESTR("go? ","?","!")),3):
String scalar: "GO! GO! GO! "
Finally, to close the "Built-in Functions" section, a few examples of time series functions. First the most obvious:
TROLL Command: do prt.(startdate(cons),enddate(cons)); STARTDATE(CONS): Date scalar: 1969A ENDDATE(CONS): Date scalar: 1995A
If you don't like those dates, you can change them:
TROLL Command: do conpre80=subrange(cons,,1979a); TROLL Command: do conpos73=subrange(cons,1974a,NA); TROLL Command: do prt.(startdate(conpos73),enddate(conpre80)); STARTDATE(CONPOS73): Date scalar: 1974A ENDDATE(CONPRE80): Date scalar: 1979A
And you can put the original series back together (and eliminate the redundancy) with the OVERLAY function:
TROLL Command: do prt.(overlay(conpre80,conpos73));
OVERLAY(CONPRE80,CONPOS73):
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 1709.07626 1769.52642 1814.21353 1907.20040
1973A : 1984.02251 1985.22548 2056.88249 2147.30268
1977A : 2218.27090 2300.84373 2359.29939 2438.70940
1981A : 2480.56499 2492.85495 2622.18767 2757.17897
1985A : 2890.91522 3004.32887 3094.54980 3217.63234
1989A : 3292.67174 3352.46735 3330.85618 3422.79566
1993A : 3523.20597 3626.66046 3713.14739
TROLL has a number of functions to deal with missing values. The following sequence creates a series with some missing values, tests for the presence of missing values, trims off the missing values, and shows the effect on the number of observations (NOB):
TROLL Command: do gdp65t87=subrange(gdp,1965a,1987a); TROLL Command: do prt.(nob(gdp65t87)); NOB(GDP65T87): Numeric scalar: 23 TROLL Command: do prt.(natest(gdp65t87)); NATEST(GDP65T87): Boolean scalar: TRUE TROLL Command: do gdpshort=natrim(gdp65t87); TROLL Command: do prt.(nob(gdpshort)); NOB(GDPSHORT): Numeric scalar: 19
Another way to deal with missing values is to interpolate or extrapolate. In the following example, TROLL extrapolates backward from the growth rate at the beginning of the series:
TROLL Command: do prt.(nagrow(gdp65t87));
NAGROW(GDP65T87):
GDP65T87 = SUBRANGE(GDP,1965A,1987A)
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1965A to 1987A (23 observations)
Time dimension -->
1965A : 2911.13147 2912.04341 2912.95563 2913.86814
1969A : 2914.78093 2915.69401 2998.88658 3152.28521
1973A : 3316.13414 3295.33595 3268.55204 3429.96575
1977A : 3584.68329 3757.35818 3852.01535 3831.26806
1981A : 3925.14073 3840.98742 3995.87775 4268.50453
1985A : 4427.40332 4560.65358 4692.32470
TROLL can also calculate overlapping ranges of non-missing data:
TROLL Command: do bounds(gdp65t87,conpos73); 1974A to 1987A
...and change periodicities (in this case, using a cubic spline to interpolate):
TROLL Command: do prt.(spatq(conpre80));
SPATQ(CONPRE80):
Numeric scalar timeseries --
Time dimension: Periodicity 4, 1969Q1 to 1979Q4 (44 observations)
Time dimension -->
1969Q1 : 414.40095 422.97969 431.55843 440.13718
1970Q1 : 440.77844 441.41970 442.70223 444.62603
1971Q1 : 447.24806 450.79621 455.32745 460.84179
1972Q1 : 467.16778 473.61967 480.02605 486.38689
1973Q1 : 492.32372 496.32261 498.00507 497.37109
1974Q1 : 495.17708 494.44863 495.94214 499.65760
1975Q1 : 505.23031 511.20140 517.20616 523.24460
1976Q1 : 529.21150 534.68601 539.56292 543.84224
1977Q1 : 547.71241 551.92722 556.67513 561.95613
1978Q1 : 567.60691 572.97416 577.89455 582.36810
1979Q1 : 586.30149 589.32151 591.33485 592.34153
Another thing TROLL functions can do is to create and reorganize data. Consider, for example, the SEQ function, which produces a sequence of numbers:
TROLL Command: do prt.(seq(10));
SEQ(10):
Numeric array --
1 space dimension: 10
Space dimension number 1 -->
[1]: 1 2 3 4
[5]: 5 6 7 8
[9]: 9 10
TROLL Command: do prt.(seq(32,212,10*9/5));
SEQ(32,212,10*9/5):
Numeric array --
1 space dimension: 11
Space dimension number 1 -->
[1]: 32 50 68 86
[5]: 104 122 140 158
[9]: 176 194 212
SEQ produces an array (actually, a column vector), but you might have wanted a time series. No problem! TROLL allows you to arbitrarily reshape data along any number of time or space dimensions. To get a linear time trend, you can reshape a column vector produced by SEQ into a scalar time series:
TROLL Command: do prt.(reshape(seq(10),1980a));
RESHAPE(SEQ(10),1980A):
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1980A to 1989A (10 observations)
Time dimension -->
1980A : 1 2 3 4
1984A : 5 6 7 8
1988A : 9 10
Or if you prefer a non-linear pattern...
TROLL Command: do prt.(10*reshape(sqrt(3+log(absv(sin(seq(-9.56,1,.628)))))));
10*RESHAPE(SQRT(3+LOG(ABSV(SIN(SEQ(-9.56,1,0.628)))))):
Numeric array --
1 space dimension: 17
Space dimension number 1 -->
[1]: 9.980549 15.004996 17.015074 17.274481
[5]: 16.224714 10.038678 14.99509 17.012808
[9]: 17.275306 16.229819 10.095796 14.98514
[13]: 17.010533 17.276124 16.234907 10.151937
[17]: 14.975145
Using the COMBINE function (abbreviated "C."), you can put together specific pieces of data:
TROLL Command: do fibb=combine(1,2,3,5,8,13);
TROLL Command: do prt.(fibb);
FIBB:
FIBB = COMBINE(1,2,3,5,8,13)
Numeric array --
1 space dimension: 6
Space dimension number 1 -->
[1]: 1 2 3 5
[5]: 8 13
TROLL Command: do whitelie=c.(fibb,0,0,0);
TROLL Command: do prt.(whitelie);
WHITELIE:
WHITELIE = C.(FIBB,0,0,0)
Numeric array --
1 space dimension: 9
Space dimension number 1 -->
[1]: 1 2 3 5
[5]: 8 13 0 0
[9]: 0
You can also generate "random" numbers...
TROLL Command: do prt.(randnorm(,,10)-randunif(,,10));
RANDNORM(NA,NA,10)-RANDUNIF(NA,NA,10):
Numeric array --
1 space dimension: 10
Space dimension number 1 -->
[1]: 0.813793 -1.101452 -0.541802 -0.215298
[5]: -1.422684 0.033928 -0.899749 -0.550727
[9]: -0.459743 -0.027697
Create a zero matrix...or a non-zero matrix...
TROLL Command: do prt.(crmat(2,4),crmat(3,3,5));
CRMAT(2,4):
Numeric array --
2 space dimensions: 2 by 4
Space dimension number 2 -->
[1,1]: 0 0 0 0
[2,1]: 0 0 0 0
CRMAT(3,3,5):
Numeric array --
2 space dimensions: 3 by 3
Space dimension number 2 -->
[1,1]: 5 5 5
[2,1]: 5 5 5
[3,1]: 5 5 5
...and add columns and rows:
TROLL Command: do prt.(addrow(addcol(crmat(3,3,5),2,4.4),3));
ADDROW(ADDCOL(CRMAT(3,3,5),2,4.4),3):
Numeric array --
2 space dimensions: 4 by 4
Space dimension number 2 -->
[1,1]: 5 5 4.4 5
[2,1]: 5 5 4.4 5
[3,1]: 5 5 4.4 5
[4,1]: NA NA NA NA
This section will go through the steps of setting up and saving a model. This example is a model of fiscal policy in which tax rates adjust gradually to move the stock of outstanding government bonds toward a target level. (Everything is expressed per unit of effective labor.) The wrinkle will be that personal consumption depends on perceived human wealth, which depends in turn on the anticipated tax rate. For now, we'll just set up the model without estimating or simulating it.
First, we declare the current model to be the one we are about to create:
TROLL Command: usemod tax1; New model: TAX1
Next, we start the model-editing task ("MODEDIT"), so we can put something in the model:
TROLL Command: modedit;The first necessary element in a model is the set of symbols it uses. In TROLL, there are several types of symbols, categorized according to the type of variables they represent. In this model, we use ENDOGENOUS, EXOGENOUS, and COEFFICIENT symbols. We begin by adding symbols for some endogenous variables, government debt (b), consumption (c), the capital stock (k), the interest rate (r), output (y), tax revenue (t), and the tax rate:
MODEDIT Command: addsym endogenous b c k r y t trate;Now some exogenous variables, government spending (g), the debt target (bt), capital's share of output (capsh), the rate of technical progress (pi), the labor force growth rate (n), and the capital asset risk premium (prem):
MODEDIT Command: addsym exogenous g bt capsh pi n prem;
And some coefficients:
MODEDIT Command: addsym coefficient a tradj;
Now the meat of the model, the equations. We will use upper case letters for equation labels, just to make the equations a little clearer. When you add an equation in TROLL, you must specify a position relative to the existing equations. Since there are no existing equations yet, the position is irrelevant, but we specify "bottom" and then continue adding equations to the bottom. The first equation is the production function:
MODEDIT Command: addeq bottom OUTPUT: y = a*(k**capsh);
Then the capital-market equilibrium condition:
MODEDIT Command: addeq bottom IRATE: r=a*capsh*(k**(capsh-1))+prem;
Now we add a few identity equations. (Note that multiple equations can be added in a single ADDEQ statement.)
MODEDIT Command: addeq bottom
(TROLL prompts, rather ambiguously here, for more information.)
'+', '-', ',', ';' or next item: TAXREV: t = trate*y, [Lbl:] Equation: GDPIDEN: k-k(-1) + (pi+n)*k(-1) = y-c-g , [Lbl:] Equation: BUDGIDEN: b-b(-1) = (r-(pi+n))*b(-1) +g-t;
The next equation is the most critical one. It describes how the tax rate adjusts to move the debt toward its target level:
MODEDIT Command: addeq bottom TAXADJ: Equation: trate-trate(-1) = Continue eq: tradj * ( ( (b-bt) - (b(-1)-bt(-1)) ) / y );
To close the model, we add a consumption block. First we'll need a few more symbols, the rate of time preference (theta), the death rate (lambda), and the stock of human wealth (h):
MODEDIT Command: addsym exogenous theta lambda, endogenous h;
Consumption depends on wealth, which includes physical capital, government bonds, and human wealth:
MODEDIT Command: addeq bottom CONS: c = (theta+lambda)*(k+b+h);
Finally, an equation describing the growth of human wealth. Rational consumption and investment behavior requires that the return on human wealth be the same as the return on physical capital. That condition determines a unique growth path for human wealth, which depends on the growth path for taxes. The explicit derivation of this equation is well beyond the scope of this Guide, but notice that the equation involves forward-looking expectations:
MODEDIT Command: addeq bottom WHUM: h(+1)-h = Continue eq: (r+lambda-pi)*h - (y - r*k - t);
That completes the model. We won't try to solve it now, just save it for later:
MODEDIT Command: filemod;
You'll recall from the beginning of this section that we named the model TAX1. Accordingly, a file called TAX1.MOD will now appear in the first nondata-writable disk database on the search list. We can use that file tomorrow, next month, or next year, whenever we decide to work with this model again. For now, though, let's just look at some simple examples of what the TROLL simulator can do.
In order to simulate, we need a model. We'll start over and enter a very simple, two-equation model.
TROLL Command: usemod ; New model: (nameless) TROLL Command: addsym endogenous x y ;
(TROLL automatically enters the model-editing task, since the ADDSYM command unambiguously belongs to MODEDIT.)
MODEDIT Command: addeq top x+2*y = 10, x-y = 1 ;
Here we have two simultaneous equations. What the simulator does, in essence, is to solve simultaneous equations. TROLL requires starting values to begin its simulation. In this case the starting values will be irrelevant, so let's just choose something easy:
MODEDIT Command: do x=1, y=1 ;
Okay, now solve the equations. (Here we tell TROLL to leave the MODEDIT task and enter the SIMULATE task.)
MODEDIT Command: simulate ;
Analyzing Model's Incidence Matrix
Analyzing Model's Block Structure
Generating Simulation Code
Use FILEMOD or SAVEMOD before USEMOD to save code.
Simulations can start from NA to NA.
SIMULATE Command: list iter all ;
SIMULATE Command: simstart 1a; dosim 1;
Date: Block: Iter: Symbol: Value: [Rel. Change:]
1A 1 0 Y 1
X 1
1 Y 3 [+1.00000e+000]
X 4 [+1.50000e+000]
Voilą. Y=3 and X=4.
Now let's try a nonlinear equation. (The "'N" notation below is a shorthand way to declare an endogenous variable "on the fly". Here we let TROLL process three separate commands from a single input line. The PRINT command tells TROLL to display the contents of the model.)
SIMULATE Command: usemod ; addeq top sin(x'n) = cos(x) ; print ;
New model: (nameless)
Symbols:
ENDOGENOUS :
X
FUNCTION :
COS SIN
Equations:
1: SIN(X) = COS(X)
MODEDIT Command: do x = 0 ;
MODEDIT Command: simulate ;
Analyzing Model's Incidence Matrix
Analyzing Model's Block Structure
Generating Simulation Code
Use FILEMOD or SAVEMOD before USEMOD to save code.
Simulations can start from NA to NA.
SIMULATE Command: list iterations all ;
SIMULATE Command: simstart 1a ; dosim 1 ;
Date: Block: Iter: Symbol: Value: [Rel. Change:]
1A 1 0 X 0
1 X 1 [+1.00000e+000]
2 X 0.782042 [-1.22308e-001]
3 X 0.785398 [+1.88339e-003]
4 X 0.785398 [-7.05851e-009]
These two examples have shown static simulations, but dynamic simulations are usually more interesting. In the following example, TROLL generates a Fibonacci sequence:
SIMULATE Command: usemod ; addeq top x'n = x(-1) + x(-2); print ; New model: (nameless) Symbols: ENDOGENOUS : X Equations: 1: X = X(-1)+X(-2) MODEDIT Command: do x = 1 ; MODEDIT Command: simulate ; Analyzing Model's Incidence Matrix Analyzing Model's Block Structure Generating Simulation Code Use FILEMOD or SAVEMOD before USEMOD to save code. Simulations can start from NA to NA. SIMULATE Command: list solutions all ;
This simulation begins in the year 3 and ends in the year 10:
SIMULATE Command: simstart 3a ; dotil 10a ; Date: Symbol: Value: 3A Solution: X 2 4A Solution: X 3 5A Solution: X 5 6A Solution: X 8 7A Solution: X 13 8A Solution: X 21 9A Solution: X 34 10A Solution: X 55
TROLL's specialty is simulation of forward-looking models. In such models, the present state of the universe depends on the future, so that the usual direction of cause-and-effect is reversed. (Typically, the mechanism for this reversed causation is foresight by rational agents who act in anticipation of the future.) One simple illustration of a forward-looking simulation is the Fibonacci sequence in reverse, as in the following model:
MODEDIT Command: usemod ; addeq top x'n = x(+1) + x(+2); print ; New model: (nameless) Symbols: ENDOGENOUS : X Equations: 1: X = X(+1)+X(+2)
The only difference between this and the previous example is that the minus-signs in the subscripts have become plus-signs. In words, the model says, "This year's X is whatever will be the sum of next year's X and the following year's X." To solve the model, we can use TROLL's stacked-time simulator, which simulates by solving multiple periods simultaneously (i.e., "stacking" multiple periods in one set of simultaneous equations). First, we initialize the data:
MODEDIT Command: do x=1; Now we enter the simulation task. Since this is a forward-looking simulation, we have to specify the algorithm ("stack") used to solve it. Also, the "stack" algorithm requires a parameter: the number of periods to solve simultaenously. To keep it simple, we choose 8, the number of periods over which we are going to simulate (as in the previous example):MODEDIT Command: simulate stack 8; Analyzing Model's Incidence Matrix Analyzing Model's Block Structure Constructing stacked-time incidence matrix and code. Simulations can start from NA to NA.
Now we proceed as before:
SIMULATE Command: list solutions all;
SIMULATE Command: simstart 3a; dotil 10a;
Date: Symbol: Value:
3A Solution: X [3A] 55
[4A] 34
[5A] 21
[6A] 13
[7A] 8
[8A] 5
[9A] 3
[10A] 2
There it is: the Fibonacci sequence in reverse.
For a slightly more practical example of foward-looking simulation, let's look at a variation on the traditional Keynesian "investment multiplier" model. To keep the model as simple as possible, we will ignore the government, foreign trade, money, prices, and just about anything else that could complicate the model. The only complication will be forward-looking behavior by consumers. We start by clearing the model workspace:
TROLL Command: usemod; New model: (nameless) TROLL Command: modedit;
To begin with, there is one exogneous variable, investment:
MODEDIT Command: addsym exogenous i;
...and two endogenous variables, income and consumption:
MODEDIT Command: addsym endogenous y c;
Without the government or foreign trade, the national income identity is simple:
MODEDIT Command: addeq bottom y=c+i;
Finally, there is consumer behavior. The agents in this model consume a constant fraction (80 percent, for this example) of their "permanent" income. A new endogenous variable, YPERM, represents consumers' estimates of their permanent income:
MODEDIT Command: addsym endogenous yperm; MODEDIT Command: addeq bottom c=.8*yperm;
Consumers estimate their permanent income primarily from their current income, but they also have some information about next year. Their estimated permanent income is a weighted average of this year's income and next year's income:
MODEDIT Command: addeq bottom yperm = .8*y + .2*y(+1);
That completes the model:
MODEDIT Command: print; Symbols: ENDOGENOUS : C Y YPERM EXOGENOUS : I Equations: 1: Y = C+I 2: C = 0.8*YPERM 3: YPERM = 0.8*Y+0.2*Y(+1)
We need some starting data to begin the simulation. The following statements generate exponential growth for income and consumption over 21 years:
MODEDIT Command: do y=exp(1+reshape(seq(21),1a)/10);
MODEDIT Command: do prt.(y);
Y:
Y = EXP(1+RESHAPE(SEQ(21),1A)/10)
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1A to 21A (21 observations)
Time dimension -->
1A : 3.00416 3.32011 3.66929 4.0552
5A : 4.48168 4.95303 5.47394 6.04964
9A : 6.68589 7.38905 8.16617 9.02501
13A : 9.97418 11.02317 12.18249 13.46373
17A : 14.87973 16.44464 18.17414 20.08553
21A : 22.19795
MODEDIT Command: do c=.8*y;
MODEDIT Command: do yperm=y;
For this example, generate some pseudo-random data for (exogenous) investment. (The "seed" argument to RANDNORM ensures that the data will be replicable.)
MODEDIT Command: do i=.2*y*(1+randnorm(1));
MODEDIT Command: do prt.(i);
I:
I = 0.2*Y*(1+RANDNORM(1))
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1A to 21A (21 observations)
Time dimension -->
1A : 1.01899 1.12615 1.24459 1.37549
5A : 1.52015 1.68003 1.85672 2.05199
9A : 2.26780 2.50631 2.76990 3.06121
13A : 3.38316 3.73897 4.13220 4.56679
17A : 5.04709 5.57789 6.16453 6.81285
21A : 7.52937
First we'll simulate by stacking the entire simulation period:
MODEDIT Command: simulate stack 20;
Analyzing Model's Incidence Matrix
Analyzing Model's Block Structure
Constructing stacked-time incidence matrix and code.
Simulations can start from 1A to 20A and must end by 20A.
SIMULATE Command: list solutions y;
SIMULATE Command: simstart 1a; dotil 20a;
Date: Symbol: Value:
1A Solution: Y [1A] 5.563001
[2A] 6.148065
[3A] 6.794658
[4A] 7.509249
[5A] 8.298981
[6A] 9.171742
[7A] 10.13623
[8A] 11.202013
[9A] 12.379567
[10A] 13.680252
[11A] 15.116123
[12A] 16.69939
[13A] 18.441034
[14A] 20.34754
[15A] 22.413363
[16A] 24.603765
[17A] 26.815996
[18A] 28.791676
[19A] 29.919413
[20A] 28.790365
To reduce the number of equations that have to be solved simultaenously, you can reduce the stack parameter:
SIMULATE Command: simulate stack 5;
Constructing stacked-time incidence matrix and code.
Simulations can start from 1A to 20A and must end by 20A.
SIMULATE Command: list solutions y;
SIMULATE Command: simstart 1a; dotil 20a;
Date: Symbol: Value:
1A Solution: Y [1A] 5.489842
[2A] 5.983457
[3A] 6.424291
[4A] 6.675923
[5A] 6.423999
6A Solution: Y [6A] 9.051219
[7A] 9.865054
[8A] 10.591866
[9A] 11.006737
[10A] 10.591384
11A Solution: Y [11A] 14.922938
[12A] 16.264724
[13A] 17.463034
[14A] 18.147041
[15A] 17.462239
16A Solution: Y [16A] 24.603765
[17A] 26.815996
[18A] 28.791676
[19A] 29.919413
[20A] 28.790365
Because the effect of forward-looking behavior decays quickly in this model, the results are not very different.
You've already seen an example of OLS estimation in TROLL, but TROLL's estimation capabilities go far beyond that. In this section, we'll look at some very simple examples of simultaneous equation estimation in TROLL. These examples use a "minimalist multiplier-accelerator model" of the US economy, in which consumption and investment are simultaneously determined, and other elements of demand are taken as exogenous. Although a more realistic model of investment could take advantage of TROLL's ability to estimate large, non-linear models with rich intertemporal specifications, this wirlwind tour will limit itself to the simplest possibility - a linear two-equation model with no lags or leads.
The data used here come from the same NIPA database used earlier, which was accessed as follows:
TROLL Command: access nipa type formdata id c:\usanipa.frm; TROLL Command: search first nipa;
The variable that drives the model is "exogenous demand," that is, demand not for personal consumption or private investment. In principle, that demand would include government demand and "net export" demand. Without attempting to disaggregate (or to define a "net export"), we'll just subtract investment and consumption from gross domestic product and use what's left over:
TROLL Command: do exdemand=gdp-invest-cons;
Before doing any simultaneous equation estimation, we have to specify a model. Although we don't intend to do a simulation, the format of the model, and the process for entering it, is exactly the same as for a simulation model. First, clear the model space:
TROLL Command: usemod; New model: (nameless)
Add symbols for the variables:
TROLL Command: addsym endogenous cons invest; MODEDIT Command: addsym exogenous exdemand;
We also need symbols for the coefficients to estimate:
MODEDIT Command: addsym coefficient a0 a1 b0 b1;
The first equation represents the "multiplier" relationship, which is derived from the consumption function. In its reduced form, the equation gives consumption as a function of "other demand," which includes both exogenous demand and (endogenous) investment:
MODEDIT Command: addeq bottom cons=a0+a1*(exdemand+invest);
The second equation represents the "accelerator" relationship, to which an analogous logic applies:
MODEDIT Command: addeq bottom invest=b0+b1*(exdemand+cons); MODEDIT Command: print; Symbols: ENDOGENOUS : CONS INVEST EXOGENOUS : EXDEMAND COEFFICIENT : A0 A1 B0 B1 Equations: 1: CONS = A0+A1*(EXDEMAND+INVEST) 2: INVEST = B0+B1*(EXDEMAND+CONS)
Now we specify some options - the estimation period (required) and the maximum number of iterations (optional, but the default won't be enough):
MODEDIT Command: bounds 1969a to 1995a; MODEDIT Command: conopt stop 100;
First we estimate by ordinary least squares, which ignores the simultaneity but provides a starting point for the more advanced methods. The OLSMOD command causes TROLL to leave the MODEDIT task and perform regressions on the equations in the completed model:
MODEDIT Command: olsmod all; ORDINARY LEAST SQUARES 1 : CONS = A0+A1*(EXDEMAND+INVEST) NOB = 27 NOVAR = 2 NCOEF = 2 RANGE: 1969A to 1995A RSQ = 0.947023 CRSQ = 0.944904 F(1/25) = 446.903387 PROB>F = 0 SER = 148.604555 SSR = 552082.842861 DW(0) = 1.128891 COND = 13.746273 MAX:HAT = 0.163032 RSTUDENT = -2.244192 DFFITS = 0.471296 COEF ESTIMATE STER TSTAT PROB>|T| A0 -1484.786935 197.604798 -7.513921 0 A1 2.779316 0.131471 21.14009 0 ORDINARY LEAST SQUARES 2 : INVEST = B0+B1*(EXDEMAND+CONS) NOB = 27 NOVAR = 2 NCOEF = 2 RANGE: 1969A to 1995A RSQ = 0.672506 CRSQ = 0.659406 F(1/25) = 51.337314 PROB>F = 0 SER = 69.11211 SSR = 119412.093844 DW(0) = 1.136274 COND = 9.52663 MAX:HAT = 0.138467 RSTUDENT = -1.837855 DFFITS = -0.591527 COEF ESTIMATE STER TSTAT PROB>|T| B0 217.329789 64.053175 3.392959 0.002307 B1 0.129394 0.018059 7.165006 0
Having completed the OLS estimations, we save the coefficients to use as starting values for the simultaneous equation estimation:
OLSMOD Command: savecoef;
Now we enter TROLL's simultaenous-equation estimator, known as GREMLIN. GREMLIN is a package containing several alternative tasks for estimating systems of equations. Here we'll start with the FIML task, which begins by setting up the model for estimation by "full-information maximum likelihood":
OLSMOD Command: fiml; ...ANALYSING MODEL ...GENERATING CODE
To save space, we will suppress detailed reporting of the optimization:
FIML Command: outlvl int 1; FIML uses an iterative process to maximize the likelihood function. Numerous options are available for such things as the starting values, the optimization algorithm, and the convergence criteria. Here we'll just accept the defaults (except for the "maximum iterations" option, which we have already set, and the starting coefficient estimates, which will be taken from the saved OLS results). FIML proceeds with the estimation: FIML Command: estimate; FIML estimation Begins *** Standard algorithm *** Jacobian is 0.00 sparse, order 2 MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2 RANGE: 1969A to 1995A OPT ALGORITHM: DAVIDON-FLETCHER-POWELL ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER LIMIT: 100 FEVALMAX: 500 Beginning Linear-Jacobian Iterations Convergence OBTAINED in 35 iterations, 74 FCN evaluations,FCN=18.6843 MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2 RANGE: 1969A to 1995A OPT ALGORITHM: DAVIDON-FLETCHER-POWELL ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER LIMIT: 100 FEVALMAX: 500 Total Iters: 35 Fevals: 74 Final FCN: 18.68435 LOG-LIKE: -328.86146
Here are the coefficient estimates, which you can compare with the OLS estimates produced earlier:
VALUE STD ERR
A0 -1658.948879 210.525413
A1 2.896423 0.140306
B0 286.031144 66.267269
B1 0.109593 0.018721
...and some statistics:
Single Equation Statistics
RSQ CRSQ SSR SER
Eqn 1 0.945342 0.943155 569604.260898 150.944263
Eqn 2 0.656757 0.643027 125154.572678 70.754384
Another GREMLIN task is "three-stage least squares," which is invoked by the THREESLS command:
FIML Command: threesls; ...ANALYSING MODEL ...GENERATING CODE THREESLS Command: outlvl int 1; THREESLS Command: estimate; 2 Stage estimation begins... MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2 RANGE: 1969A to 1995A OPT ALGORITHM: DAVIDON-FLETCHER-POWELL ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER LIMIT: 100 FEVALMAX: 500 Convergence OBTAINED in 6 iterations, 11 FCN evaluations, FCN=-6.5293531e-012 MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2 RANGE: 1969A to 1995A OPT ALGORITHM: DAVIDON-FLETCHER-POWELL ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER LIMIT: 6 FEVALMAX: 500 Total Iters: 6 Fevals: 11 Final FCN: -6.5293531e-012
That's the first half of the procedure, and these are the preliminary results:
VALUE STD ERR
A0 -1658.948879 1.449408
A1 2.896423 0.000966
B0 286.031144 0.973607
B1 0.109593 0.000275
Single Equation Statistics
RSQ CRSQ SSR SER
Eqn 1 0.945342 0.943155 569604.260883 150.944263
Eqn 2 0.656757 0.643027 125154.572648 70.754384
To continue...
3 Stage estimation begins...
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 100 FEVALMAX: 500
Convergence OBTAINED in 100 iterations, 201 FCN evaluations,
FCN=-3.5032956e-016
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 100 FEVALMAX: 500
Total Iters: 100 Fevals: 201 Final FCN: -3.5032956e-016
The final coefficient estimates are very similar to the FIML results:
VALUE STD ERR
A0 -1658.948879 210.520997
A1 2.896423 0.140302
B0 286.031144 66.286481
B1 0.109593 0.018728
Single Equation Statistics
RSQ CRSQ SSR SER
Eqn 1 0.940807 0.93844 616856.325942 157.080403
Eqn 2 -0.104968 -0.149166 402897.701068 126.948446
Another method available in GREMLIN is Zellner's "Seemingly Unrelated Regressions", invoked with the ZELLNER command:
THREESLS Command: zellner;
...ANALYSING MODEL
...GENERATING CODE
ZELLNER Command: outlvl int 1;
ZELLNER Command: estimate;
2 Stage estimation begins...
Seemingly unrelated equations (ZELLNER) case
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 100 FEVALMAX: 500
Convergence OBTAINED in 5 iterations, 10 FCN evaluations,
FCN= 671494.936704
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 5 FEVALMAX: 500
Total Iters: 5 Fevals: 10 Final FCN: 671494.9367 LOG-LIKE: -317.4535
VALUE STD ERR
A0 -1484.786935 1.329736
A1 2.779316 0.000885
B0 217.329789 0.926801
B1 0.129394 0.000261
Single Equation Statistics
RSQ CRSQ SSR SER
Eqn 1 0.947023 0.944904 552082.842861 148.604555
Eqn 2 0.672506 0.659406 119412.093844 69.11211
3 Stage estimation begins...
Seemingly unrelated equations (ZELLNER) case
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 100 FEVALMAX: 500
Convergence OBTAINED in 7 iterations, 14 FCN evaluations,
FCN= 53.10385
MODEL: CURRENT NOB: 27 NOVAR: 4 NEQ: 2
RANGE: 1969A to 1995A
OPT ALGORITHM: DAVIDON-FLETCHER-POWELL
ESCALE: 100000 RADIUS: 1 CONCR: 0.001 ITER
LIMIT: 7 FEVALMAX: 500
Total Iters: 7 Fevals: 14 Final FCN: 53.10385 LOG-LIKE: -316.98111
VALUE STD ERR
A0 -1537.085898 187.189308
A1 2.814482 0.124499
B0 184.572979 60.698883
B1 0.138835 0.017101
Single Equation Statistics
RSQ CRSQ SSR SER
Eqn 1 0.946871 0.944746 553662.812995 148.817044
Eqn 2 0.668926 0.655683 120717.579224 69.488871
Among TROLL's most valuable features are its extensibility and its potential for automation. TROLL can do a lot by itself, but it may not always know how to do exactly what you want. Because of TROLL's programming facilities, this situation need not limit you: you can teach TROLL to do what you want. Even if TROLL already knows how to do what you want, you may find yourself repeatedly going through the same sequence of steps, perhaps with slight variations. Here also TROLL's programming facilities can help.
Another advantage provided by TROLL programming is the ability to share techniques conveniently among users. In many cases, you may find that someone has already written a TROLL program to do what you want. In some cases, you may want to share a methodology that you have used, but you may prefer not to spend time explaining how to do it. If you have implemented your methodology as a TROLL program, then it can be ready for immediate re-use.
TROLL programs come in two varieties, "macros" and "user-defined functions." Macros might also be called "user-defined commands," since they work very much like TROLL commands. In fact, several macros are already included in TROLL as commands. User-defined functions, as the name implies, work like TROLL functions.
When you are entering TROLL commands, you can recognize a macro by the ampersand (&) at the beginning of the name. Aside from the ampersand, you won't see much difference between macros and ordinary commands.
One macro included with troll is &PRTDATA, which will normally display a dataset on your terminal screen. For example, suppose you have accessed the USANIPA.FRM file and placed its alias on the search list. Then you can do the following:
TROLL Command: &prtdata cons;
NIPA_CONS:
CONS = CONS
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 1709.07626 1769.52642 1814.21353 1907.20040
1973A : 1984.02251 1985.22548 2056.88249 2147.30268
1977A : 2218.27090 2300.84373 2359.29939 2438.70940
1981A : 2480.56499 2492.85495 2622.18767 2757.17897
1985A : 2890.91522 3004.32887 3094.54980 3217.63234
1989A : 3292.67174 3352.46735 3330.85618 3422.79566
1993A : 3523.20597 3626.66046 3713.14739
So far, the macro may not seem to have much advantage over the DFLIST function (called in a statement like "DO PRT.(DFLIST(CONS));". However, &PRTDATA can do a lot more than DFLIST can do. For example, if you want to look at all variables containing the letter N, you can use the asterisk as a "wild card character" to represent any letter or (possbily null) sequence of letters:
TROLL Command: &prtdata(*N*);
NIPA_CONS:
CONS = CONS
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 1709.07626 1769.52642 1814.21353 1907.20040
1973A : 1984.02251 1985.22548 2056.88249 2147.30268
1977A : 2218.27090 2300.84373 2359.29939 2438.70940
1981A : 2480.56499 2492.85495 2622.18767 2757.17897
1985A : 2890.91522 3004.32887 3094.54980 3217.63234
1989A : 3292.67174 3352.46735 3330.85618 3422.79566
1993A : 3523.20597 3626.66046 3713.14739
NIPA_INVEST:
INVEST = INVEST
Numeric scalar timeseries --
Time dimension: Periodicity 1, 1969A to 1995A (27 observations)
Time dimension -->
1969A : 509.28453 470.10831 519.07654 576.17583
1973A : 643.19044 589.55518 467.24260 564.48194
1977A : 651.91469 721.36608 722.12479 577.76256
1981A : 627.76277 538.26011 586.72186 757.62755
1985A : 750.27456 738.41929 747.17498 751.06644
1989A : 783.10274 738.66821 668.10227 715.59117
1993A : 774.12084 886.85884 913.19376
&PRTDATA can do various other things too, and it's too complex to examine in detail here. To get an idea of how macros work, consider a very simple macro designed to list the names of the variables in a "formdata" file on the host system. The text of that macro is in a file called FMLS.SRC, which reads as follows:
// FMLS: Macro to list the variables in a "formdata" file
// Usage: &FMLS file
// where the file is named file.frm
addfun main;
procedure main()
begin;
get formdb;
formname = formdb || ".frm";
>>access ff type formdata id &formname;
>>search ff;
>>do prt.(dflist("ff"));
>>delaccess ff;
end;
The lines beginning with "//" are not used by TROLL; they're just comments to explain the file's purpose to someone who might be reading it. The lines from "addfun..." to "begin" are just there to tell TROLL that this is a macro. The important part starts with the "get formdb" line. We will examine those lines in detail presently, but first let's look at this macro in action. Before you can use it, you need to convert it from text into a form that TROLL understands. Assuming you have the FMLS.SRC file in an accessed disk directory whose alias appears on your search list (typically the "." directory), the following command makes the macro available to your TROLL session:
TROLL Command: compile fmls;
TROLL Compiler: Rel. 1.0
END OF COMPILATION
ERRORS: 0
WARNINGS: 0
Now, if you have USANIPA.FRM in a searchable disk directory, you can do the following:
TROLL Command: &fmls usanipa;
DFLIST("ff"):
String array --
1 space dimension: 3
Space dimension number 1 -->
[1]: "CONS" "GDP" "INVEST"
Let's look now at the statements in the macro file:
get formdb;
That statement tells the macro to obtain an input from the user. Typically, the user will pass the input to the macro by typing it after the macro name. In the example above, the input is "usanipa". The next statement in the macro appends the ".frm" extension on to the end of the argument and stores the result in a variable called "formname" (of which the contents will be called "&formname"):
formname = formdb || ".frm";
In the example above, the result is "usanipa.frm". The next four statements, which begin with ">>" tell the macro to pass commands to TROLL as if they had been typed on the TROLL command line:
>>access ff type formdata id &formname;
Before passing the command to TROLL, the macro substitutes the value of "formname" for "&formname". In the example, the value of "formname" is "usanipa.frm", so TROLL receives the following command from the macro:
access ff type formdata id usanipa.frm;
That command gives TROLL access to "usanipa.frm", using the alias "ff". The macro then passes the subsequent commands to TROLL (with no substitution required, except stripping off the ">>"), just as if they had been enetered by a user:
search ff;
do prt.(dflist("ff"));
delaccess ff;
Thus TROLL prints out the contents of "ff" and then removes it from the access list.
User-defined functions work exactly like built-in functions, except that a user-defined function will have the suffix "'F" to indicate that it is user-defined. Consider a user-defined function called "DISTANCE" that calculates the distance from the origin of a point in two-dimensional space. The function takes two arguments, which represent the X and Y coordinates of the point. Thus, you could compute the distance from the origin to the point (5,3) by typing "DISTANCE'F(5,3);" at the TROLL prompt. The text file DISTANCE.SRC implements the DISTANCE function as follows:
addfun main;
procedure main(x,y)
{
return( sqrt(x**2+y**2));
}
As with the macro, you can ignore the "addfun main" line for now. Before explaining the rest, let's look at the function in action. You "compile" a function in exactly the same way as a macro:
TROLL Command: compile distance;
TROLL Compiler: Rel. 1.0
END OF COMPILATION
ERRORS: 0
WARNINGS: 0
Now you can run it just as described in the text above:
TROLL Command: do prt.(distance'f(5,3)); DISTANCE(5,3): Numeric scalar: 5.830952
Voilą.
Back to the text of the function. The "procedure" line first indicates that this function is the "main" function in this file. (In this case it also happens to be the only one.) The main function, once compiled, will be available directly to TROLL. Other functions in the file (if any existed) would be available only within the file itself.
The "procedure" line also indicates the arguments to the funciton, which it calls "x" and "y". The names "x" and "y" are arbitrary. They are replaced by the values of the actual arguments when the function is used.
The braces ("{" and "}") around the rest of the function simply tell where it begins and ends. In this case, the function contains only one statement, a "return" statement, which tells the function to return a value. The value to return is the square root of the sums of the squares of the two arguments. ("**" represents exponentiation).
When called with the arguments 5 and 3, the fuction returns the square root of 5-squared plus 3-squared, or 5.830952. This value is then passed to the "PRT." fuction, which displays it on the computer screen.
Functions, of course, can do much more than computing and returning values. Functions (and macros) can include programming logic, using constructions like "IF..THEN..ELSE" to execute statements conditionally, and "WHILE" or "FOR" to repeat statements in a loop. If necessary, functions and macros can operate directly on external variables; they can test for TROLL error conditions; they can retreive, store, or display data. In general, TROLL functions and macros can do most of the things that a program in a typical procedural programming language like FORTRAN or C can do.
This completes the whirlwind tour of Portanble TROLL. Hopefully the tour has taught you something about what Portable TROLL can do and how to use it. Hopefully you've gotten a little more comfortable using TROLL. Don't worry if there were things you didn't understand or if the tour didn't seem to cover what you need to know. This is only Chapter 1. The rest of this book will contain more complete explanations and comprehensive coverage.
If you have been reading this Guide from the beginning, you may want to pause here and consider what to read next. For example, if you feel comfortable with the syntax and conventions of TROLL already, you may prefer to skip or skim the next chapter and use it only as a backup reference. If there is a particular topic that you want to learn more about, you could go directly to the appropriate chapter or section.
If you feel quite comfortable TROLL now and you're the kind of person who likes to just do things instead of reading about them, you could just start using TROLL. The Reference Manual and the Programming Language manual should contain most of the specific information you need. If you get stuck on a particular topic, you could come back and read about it in here. If you have specific questions, you may find them in the FAQ list, or you can ask other TROLL users or your TROLL trainer or consultant, if you have one. If necessary, you can get the information straight from the source: the same people who develop and maintain TROLL are available for user support through various channels.
On the other hand, if you feel like you're on shaky ground and would like to develop a firm foundation before using TROLL on your own, then by all means read on. Although the remaining chapters can be used separately, they are also intended to provide a logical sequence wherein each chapter builds on the knowledge from the prvevious chpaters.
So much for the preliminaries. Let the games begin!