The Basics of Optional Arguments in GAUSS Procedures

Introduction

Optional input arguments can make your statistical computing more efficient and enjoyable. GAUSS version 20 added a new suite of tools to make it easy for you to add optional input arguments to your GAUSS procedures.

In this blog post we will show you how to easily:

  1. Create procedures that can accept optional inputs.
  2. Check for and count the number of optional inputs.
  3. Set default values.
  4. Pass optional inputs to other procedures and functions.

Basic GAUSS Procedure without Optional Inputs

We’ll start by creating a simple toy GAUSS procedure that does not use optional arguments.

// Run procedure
myProc(1.1, 2.2, 3.3);

// Define procedure
proc (0) = myProc(a, b, c);
    print a;
    print b;
    print c;
endp;

If we run the code above, we will get the following output:

1.1
2.2
3.3

To modify this procedure to accept optional arguments, we need to make the following changes:

  1. Modify the procedure declaration to specify the required arguments and allow optional arguments to be passed in.
  2. If desired, check to see if any optional arguments were passed in.
  3. Access the optional arguments.

Procedure Declaration with Optional Arguments

The procedure declaration is the first line of the procedure. The procedure declaration from our initial procedure was:

// Procedure declaration
proc (0) = myProc(a, b, c);

Now we will modify our original procedure to make a the only required input. The new procedure declaration will look like this:

// Procedure declaration with optional inputs
proc (0) = myProc(a, ...);

In the procedure declaration, above, a is a required input as it was before. However, we have replaced b and c with .... The triple dots represent the optional arguments. The triple dots ...:

  • Allow any number of optional arguments to be passed in.
  • Must be the final input in the procedure declaration.

Checking for Optional Inputs in GAUSS Procedures

The GAUSS function dynargsCount returns the number of optional arguments passed into the procedure. dynargsCount may only be called inside of a GAUSS procedure and does not take any inputs. For example:

a = 9;
b = 3.14;
c = 2.54;

print "call 1";
myProc(a);

print "call 2";
myProc(a, b);

print "call 3";
myProc(a, b, c);

// Procedure declaration with optional inputs
proc (0) = myProc(a, ...);
    local n_dynargs;

    // Notice that you do not pass ‘...’
    // into ‘dynargsCount’
    n_dynargs = dynargsCount();

    print "Number of optional inputs = " n_dynargs;
    print "---------";
endp;

Will print the following output:

call 1
Number of optional inputs =        0.0
---------
call 2
Number of optional inputs =        1.0
---------
call 3
Number of optional inputs =        2.0
---------

This allows you to add logic which depends on the number of optional arguments that were passed into your procedure.

Accessing Optional Arguments in GAUSS Procedures

You can access optional arguments in GAUSS procedures by:

  1. Using the dynargsGet function.
  2. Passing the triple dots, ..., to another function.

Retrieving Optional Input Arguments with dynargsGet

The dynargsGet procedure returns specified optional arguments. It requires one input that specifies the index, or index range of optional arguments to return. For example:

a = 9;
b = 3.14;
c = 2.54;

print "call 1";
myProc(a);

print "call 2";
myProc(a, b);

print "call 3";
myProc(a, b, c);

// Procedure declaration with optional inputs
proc (0) = myProc(a, ...);
    // Since ‘b’ and ‘c’ are not declared as inputs
    // in the procedure declaration, they must be
    // declared as local variables
    local b, c, idx;

    // The range of optional inputs we want to return
    idx = { 1, 2 };

    { b, c } = dynargsGet(idx);

    print "a = " a;
    print "b = " b;
    print "c = " c;
    print "---------";
endp;

This time, the code will print out:

call 1
a =        9.00
b =          {}
c =          {}
---------
call 2
a =        9.00
b =        3.14
c =          {}
---------
call 3
a =        9.00
b =        3.14
c =        2.54
---------

As we see above, a is passed through as we would expect each time. In "call 1", neither b or c were passed into myProc. We can see that GAUSS printed their contents as empty curly braces, {}. This indicates that they were empty matrices.

If an optional input argument requested by dynargsGet is not supplied, by default an empty matrix will be returned in its place. We can check for empty matrices with the GAUSS function, isempty. For example:

// Create an empty matrix
z = {};

// Check to see if `z` is an empty matrix
if isempty(z);
    print "z is an empty matrix";
else;
    print "z is not an empty matrix";
endif;

As you may have guessed, the above code will print:

z is an empty matrix

Setting Default Values with dynargsGet

While we can use isempty and if statements to handle the optional inputs, it is often simpler to set default values.

Fortunately, dynargsGet allows us to specify default values for the optional arguments which are not supplied. To specify default values with dynargsGet, simply add them as a comma-separated list of inputs after the required index input.

There are a few things to remember when specifying default values:

  • If default values are specified for any requested inputs, they must be specified for all optional inputs.
  • The default values may be any GAUSS type, including structures, arrays, strings, string arrays as well as sparse and dense matrices.

We can set default values for our toy example, like this:

a = 9;
b = 3.14;
c = 2.54;

print "call 1";
myProc(a);

print "call 2";
myProc(a, b);

print "call 3";
myProc(a, b, c);

// Procedure declaration with optional inputs
proc (0) = myProc(a, ...);
    // Since ‘b’ and ‘c’ are not declared as inputs
    // in the procedure declaration, they must be
    // declared as local variables
    local b, c, idx;

    // The range of optional inputs we want to return
    idx = { 1, 2 };

    // If ‘b’ or ‘c’ are not passed in, return
    // 29 or 33 respectively
    { b, c } = dynargsGet(idx, 29, 33);

    print "a = " a;
    print "b = " b;
    print "c = " c;
    print "---------";
endp;

This time our code will return:

call 1
a =     9.00
b =    29.00
c =    33.00
---------
call 2
a =     9.00
b =     3.14
c =    33.00
---------
call 3
a =     9.00
b =     3.14
c =     2.54
---------

Passing Optional Inputs to other GAUSS Procedures

While any input arguments accessed by dynargsGet can be passed to other procedures, it is important to know that the triple dots, ..., can also be passed directly into other procedures.

Passing triple dots, ..., to another procedure is just as if you passed a comma-separated list of the arguments in ....

For example:

X_1 = initMat1(3.14, 5, 2);

X_2 = initMat2(3.14, 5, 2);

// Procedure declaration with only optional inputs
proc (1) = initMat1(val, ...);
    local X;

    X = val + zeros(...);

    retp(X);
endp;

// Procedure declaration with only required inputs
proc (1) = initMat2(val, r, c);
    local X;

    X = val + zeros(r, c);

    retp(X);
endp;

The calls to initMat1 and initMat2 will behave the same.

Practical Example with Optional Arguments

Now that we’ve seen the basics of using optional inputs to GAUSS procedures, let’s work through a more practical example. We’ll create two procedures that will work together to simulate a linear model.

Our first procedure will create a random normal matrix, with the option to specify the mean and standard deviation of the variables.

/*
** Inputs: r  - Required input. Number of rows.
**         c  - Required input. Number of columns.
**         mu - Optional input. Mean of the simulated columns.
**              Default = 0.
**         sd - Optional input. Standard deviation of the 
**              simulated columns. Default = 1.
*/
proc (1) = rndNormal(r, c, ...);
    local X, mean, sd;

    // If a 3rd input is passed in, assign it
    // to ‘mean’. Otherwise set ‘mean’ equal to 0.
    // If a 4th input is passed in, assign it
    // to `sd`. Otherwise set ‘sd’ equal to 1.
    { mean, sd } = dynargsGet(1|2, 0, 1);

    // Compute a random matrix with the
    // specified mean and sd.
    X = (rndn(r, c) .* sd) + mean;

    retp(X);
endp;

Here are a few examples of how we could call this procedure:

// Create a 100x4 random normal matrix
// with mean=0 and sd=1
X_1 = rndNormal(100, 4);

// Create a 130x2 random normal matrix
// with mean=3.7 and sd=1
X_2 = rndNormal(130, 2, 3.7);

// Create a 74x5 random normal matrix
// with mean=-2 and sd=3
X_3 = rndNormal(74, 5, -2, 3);

Next, we’ll create a procedure that will use our rndNormal procedure to simulate linear models.

/*
** Inputs: b_true  - Required input. True parameter values of
**                   the simulated linear model.
**         nobs  - Required input. The number of observations
**                 to simulate.
**         alpha_true - Optional input. True intercept of the
**                      simulated linear model. Default = 0.
**         err_sd - Optional input. Standard deviation of the 
**                  error term. Default = 1.
*/
proc (1) = simulateLM(b_true, nobs, ...);
    local X, err, nvars, alpha_plus_err, y;

    // Find number of desired variables
    nvars = rows(b_true);

    // Simulate variables with
    // mean = 0, sd = 1
    X = rndNormal(nobs, nvars);

    // Simulate error term and add intercept
    // if it was passed in.
    alpha_plus_err = rndNormal(nobs, 1, ...);

    y = X * b_true + alpha_plus_err;

    retp(y);
endp;

Here are a few examples of how our simulateLM procedure can be used:

b = { 0.8, -1.1, 0.2 };
n = 10;

/*
** Simulate linear model:
**     - Without intercept
**     - With error term sd equal to 1
*/
y_1 = simulateLM(b, n);

/*
** Simulate linear model:
**     - With intercept
**     - With error term sd equal to 1
*/
alpha = 2.3;
y_2 = simulateLM(b, n, alpha);

/*
** Simulate linear model:
**     - With intercept
**     - With error term sd equal to 3
*/
alpha = 2.3;
err_sd = 3;
y_3 = simulateLM(b, n, alpha, err_sd);

Conclusion

Congratulations! You should now be able to start creating GAUSS procedures with optional input arguments. You have learned how to:

  1. Allow optional inputs, by adding triple dots, ..., to the procedure declaration.
  2. Find out how many optional arguments were passed in by using dynargsCount.
  3. Access the optional arguments and set default values with dynargsGet.
  4. Pass optional arguments to other GAUSS procedures.
Leave a Reply