PROC MODEL provides several features to aid in finding errors in the model program. These debugging features are not usually needed; most models can be developed without them.
The example model program that follows is used in the following sections to illustrate the diagnostic and debugging capabilities. This example is the estimation of a segmented model.
/*--- Diagnostics and Debugging ---*/
*---------Fitting a Segmented Model using MODEL----*
| | |
| y | quadratic plateau |
| | y=a+b*x+c*x*x y=p |
| | ..................... |
| | . : |
| | . : |
| | . : |
| | . : |
| | . : |
| +-----------------------------------------X |
| x0 |
| |
| continuity restriction: p=a+b*x0+c*x0**2 |
| smoothness restriction: 0=b+2*c*x0 so x0=-b/(2*c)|
*--------------------------------------------------*;
title 'QUADRATIC MODEL WITH PLATEAU';
data a;
input y x @@;
datalines;
.46 1 .47 2 .57 3 .61 4 .62 5 .68 6 .69 7
.78 8 .70 9 .74 10 .77 11 .78 12 .74 13 .80 13
.80 15 .78 16
;
proc model data=a list xref listcode;
parms a 0.45 b 0.5 c -0.0025;
x0 = -.5*b / c; /* join point */
if x < x0 then /* Quadratic part of model */
y = a + b*x + c*x*x;
else /* Plateau part of model */
y = a + b*x0 + c*x0*x0;
fit y;
run;
The LIST option produces a listing of the model program. The statements are printed one per line with the original line number and column position of the statement.
The program listing from the example program is shown in Figure 90.
Figure 90: LIST Output for Segmented Model
| QUADRATIC MODEL WITH PLATEAU |
| Listing of Compiled Program Code | ||
|---|---|---|
| Stmt | Line:Col | Statement as Parsed |
| 1 | 4524:4 | x0 = (-0.5 * b) / c; |
| 2 | 4525:4 | if x < x0 then |
| 3 | 4526:7 | PRED.y = a + b * x + c * x * x; |
| 3 | 4526:7 | RESID.y = PRED.y - ACTUAL.y; |
| 3 | 4526:7 | ERROR.y = PRED.y - y; |
| 4 | 4527:4 | else |
| 5 | 4528:7 | PRED.y = a + b * x0 + c * x0 * x0; |
| 5 | 4528:7 | RESID.y = PRED.y - ACTUAL.y; |
| 5 | 4528:7 | ERROR.y = PRED.y - y; |
The LIST option also shows the model translations that PROC MODEL performs. LIST output is useful for understanding the code generated by the %AR and the %MA macros.
The XREF option produces a cross-reference listing of the variables in the model program. The XREF listing is usually used in conjunction with the LIST option. The XREF listing does not include derivative (@-prefixed) variables. The XREF listing does not include generated assignments to equation variables, PRED., RESID., and ERROR.-prefixed variables, unless the DETAILS option is used.
The cross-reference from the example program is shown in Figure 91.
Figure 91: XREF Output for Segmented Model
| QUADRATIC MODEL WITH PLATEAU |
| Cross Reference Listing For Program | |||
|---|---|---|---|
| Symbol----------- | Kind | Type | References (statement)/(line):(col) |
| a | Var | Num | Used: 3/69682:13 5/69684:13 |
| b | Var | Num | Used: 1/69680:12 3/69682:16 5/69684:16 |
| c | Var | Num | Used: 1/69680:15 3/69682:22 5/69684:23 |
| x0 | Var | Num | Assigned: 1/69680:15 |
| Used: 2/69681:11 5/69684:16 5/69684:23 5/69684:26 | |||
| x | Var | Num | Used: 2/69681:11 3/69682:16 3/69682:22 3/69682:24 |
| PRED.y | Var | Num | Assigned: 3/69682:19 5/69684:20 |
The LISTCODE option lists the model code and derivatives tables produced by the compiler. This listing is useful only for debugging and should not normally be needed.
LISTCODE prints the operator and operands of each operation generated by the compiler for each model program statement. Many of the operands are temporary variables generated by the compiler and given names such as #temp1. When derivatives are taken, the code listing includes the operations generated for the derivatives calculations. The derivatives tables are also listed.
A LISTCODE option prints the transformed equations from the example shown in Figure 92 and Figure 93.
Figure 92: LISTCODE Output for Segmented Model—Statements as Parsed
| Derivatives | ||
|---|---|---|
| WRT-Variable | Object-Variable | Derivative-Variable |
| a | RESID.y | @RESID.y/@a |
| b | RESID.y | @RESID.y/@b |
| c | RESID.y | @RESID.y/@c |
| Listing of Compiled Program Code | ||
|---|---|---|
| Stmt | Line:Col | Statement as Parsed |
| 1 | 4524:4 | x0 = (-0.5 * b) / c; |
| 1 | 4524:4 | @x0/@b = -0.5 / c; |
| 1 | 4524:4 | @x0/@c = - x0 / c; |
| 2 | 4525:4 | if x < x0 then |
| 3 | 4526:7 | PRED.y = a + b * x + c * x * x; |
| 3 | 4526:7 | @PRED.y/@a = 1; |
| 3 | 4526:7 | @PRED.y/@b = x; |
| 3 | 4526:7 | @PRED.y/@c = x * x; |
| 3 | 4526:7 | RESID.y = PRED.y - ACTUAL.y; |
| 3 | 4526:7 | @RESID.y/@a = @PRED.y/@a; |
| 3 | 4526:7 | @RESID.y/@b = @PRED.y/@b; |
| 3 | 4526:7 | @RESID.y/@c = @PRED.y/@c; |
| 3 | 4526:7 | ERROR.y = PRED.y - y; |
| 4 | 4527:4 | else |
| 5 | 4528:7 | PRED.y = a + b * x0 + c * x0 * x0; |
| 5 | 4528:7 | @PRED.y/@a = 1; |
| 5 | 4528:7 | @PRED.y/@b = x0 + b * @x0/@b + (c * @x0/@b * x0 + c * x0 * @x0/@b); |
| 5 | 4528:7 | @PRED.y/@c = b * @x0/@c + ((x0 + c * @x0/@c) * x0 + c * x0 * @x0/@c); |
| 5 | 4528:7 | RESID.y = PRED.y - ACTUAL.y; |
| 5 | 4528:7 | @RESID.y/@a = @PRED.y/@a; |
| 5 | 4528:7 | @RESID.y/@b = @PRED.y/@b; |
| 5 | 4528:7 | @RESID.y/@c = @PRED.y/@c; |
| 5 | 4528:7 | ERROR.y = PRED.y - y; |
Figure 93: LISTCODE Output for Segmented Model—Compiled Code
| 1 Stmt ASSIGN | line 4524 column 4. (1) arg=x0 argsave=x0 | |
| Source Text: | x0 = -.5*b / c; | |
| Oper * | at 4524:12 (30,0,2). | * : ##dbl1 <- -0.5 b |
| Oper / | at 4524:15 (31,0,2). | / : x0 <- ##dbl1 c |
| Oper eeocf | at 4524:15 (18,0,1). | eeocf : _DER_ <- _DER_ |
| Oper / | at 4524:15 (31,0,2). | / : @x0/@b <- -0.5 c |
| Oper - | at 4524:15 (24,0,1). | - : @1dt1_2 <- x0 |
| Oper / | at 4524:15 (31,0,2). | / : @x0/@c <- @1dt1_2 c |
| 2 Stmt IF | line 4525 column 4. (2) arg=##dbl1 argsave=##dbl1 | ref.st=ASSIGN stmt number 5 at 4528:7 |
| Source Text: | if x < x0 then | |
| Oper < | at 4525:11 (36,0,2). | < : ##dbl1 <- x x0 |
| 3 Stmt ASSIGN | line 4526 column 7. (1) arg=PRED.y argsave=y | |
| Source Text: | /* Quadratic part of model */ y = a + b*x + c*x*x; | |
| Oper * | at 4526:16 (30,0,2). | * : ##dbl1 <- b x |
| Oper + | at 4526:13 (32,0,2). | + : ##dbl2 <- a ##dbl1 |
| Oper * | at 4526:22 (30,0,2). | * : ##dbl3 <- c x |
| Oper * | at 4526:24 (30,0,2). | * : ##dbl4 <- ##dbl3 x |
| Oper + | at 4526:19 (32,0,2). | + : PRED.y <- ##dbl2 ##dbl4 |
| Oper eeocf | at 4526:19 (18,0,1). | eeocf : _DER_ <- _DER_ |
| Oper = | at 4526:19 (1,0,1). | = : @PRED.y/@a <- 1 |
| Oper = | at 4526:19 (1,0,1). | = : @PRED.y/@b <- x |
| Oper * | at 4526:24 (30,0,2). | * : @1dt1_1 <- x x |
| Oper = | at 4526:19 (1,0,1). | = : @PRED.y/@c <- @1dt1_1 |
| 3 Stmt Assign | line 4526 column 7. (1) arg=RESID.y argsave=y | |
| Oper - | at 4526:7 (33,0,2). | - : RESID.y <- PRED.y ACTUAL.y |
| Oper eeocf | at 4526:7 (18,0,1). | eeocf : _DER_ <- _DER_ |
| Oper = | at 4526:7 (1,0,1). | = : @RESID.y/@a <- @PRED.y/@a |
| Oper = | at 4526:7 (1,0,1). | = : @RESID.y/@b <- @PRED.y/@b |
| Oper = | at 4526:7 (1,0,1). | = : @RESID.y/@c <- @PRED.y/@c |
| 3 Stmt Assign | line 4526 column 7. (1) arg=ERROR.y argsave=y | |
| Oper - | at 4526:7 (33,0,2). | - : ERROR.y <- PRED.y y |
| 4 Stmt ELSE | line 4527 column 4. (9) | ref.st=FIT stmt number 5 at 4530:4 |
| Source Text: | else | |
| 5 Stmt ASSIGN | line 4528 column 7. (1) arg=PRED.y argsave=y | |
| Source Text: | /* Plateau part of model */ y = a + b*x0 + c*x0*x0; | |
| Oper * | at 4528:16 (30,0,2). | * : ##dbl1 <- b x0 |
| Oper + | at 4528:13 (32,0,2). | + : ##dbl2 <- a ##dbl1 |
| Oper * | at 4528:23 (30,0,2). | * : ##dbl3 <- c x0 |
| Oper * | at 4528:26 (30,0,2). | * : ##dbl4 <- ##dbl3 x0 |
| Oper + | at 4528:20 (32,0,2). | + : PRED.y <- ##dbl2 ##dbl4 |
| Oper eeocf | at 4528:20 (18,0,1). | eeocf : _DER_ <- _DER_ |
| Oper = | at 4528:20 (1,0,1). | = : @PRED.y/@a <- 1 |
| Oper * | at 4528:16 (30,0,2). | * : @1dt1_1 <- b @x0/@b |
| Oper + | at 4528:16 (32,0,2). | + : @1dt1_2 <- x0 @1dt1_1 |
| Oper * | at 4528:23 (30,0,2). | * : @1dt1_3 <- c @x0/@b |
| Oper * | at 4528:26 (30,0,2). | * : @1dt1_4 <- @1dt1_3 x0 |
| Oper * | at 4528:26 (30,0,2). | * : @1dt1_5 <- ##dbl3 @x0/@b |
| Oper + | at 4528:26 (32,0,2). | + : @1dt1_6 <- @1dt1_4 @1dt1_5 |
| Oper + | at 4528:20 (32,0,2). | + : @PRED.y/@b <- @1dt1_2 @1dt1_6 |
| Oper * | at 4528:16 (30,0,2). | * : @1dt1_8 <- b @x0/@c |
| Oper * | at 4528:23 (30,0,2). | * : @1dt1_9 <- c @x0/@c |
| Oper + | at 4528:23 (32,0,2). | + : @1dt1_10 <- x0 @1dt1_9 |
| Oper * | at 4528:26 (30,0,2). | * : @1dt1_11 <- @1dt1_10 x0 |
| Oper * | at 4528:26 (30,0,2). | * : @1dt1_12 <- ##dbl3 @x0/@c |
| Oper + | at 4528:26 (32,0,2). | + : @1dt1_13 <- @1dt1_11 @1dt1_12 |
| Oper + | at 4528:20 (32,0,2). | + : @PRED.y/@c <- @1dt1_8 @1dt1_13 |
| 5 Stmt Assign | line 4528 column 7. (1) arg=RESID.y argsave=y | |
| Oper - | at 4528:7 (33,0,2). | - : RESID.y <- PRED.y ACTUAL.y |
| Oper eeocf | at 4528:7 (18,0,1). | eeocf : _DER_ <- _DER_ |
| Oper = | at 4528:7 (1,0,1). | = : @RESID.y/@a <- @PRED.y/@a |
| Oper = | at 4528:7 (1,0,1). | = : @RESID.y/@b <- @PRED.y/@b |
| Oper = | at 4528:7 (1,0,1). | = : @RESID.y/@c <- @PRED.y/@c |
| 5 Stmt Assign | line 4528 column 7. (1) arg=ERROR.y argsave=y | |
| Oper - | at 4528:7 (33,0,2). | - : ERROR.y <- PRED.y y |