Wednesday, January 14, 2026

Programming an estimation command in Stata: Writing a C++ plugin


This submit is the third in a collection that illustrates tips on how to plug code written in one other language (like C, C++, or Java) into Stata. This method is called writing a plugin or as writing a dynamic-link library (DLL) for Stata.

On this submit, I write a plugin in C++ that implements the calculations carried out by mymean_work() in mymean11.ado, mentioned in Programming an estimation command in Stata: Making ready to jot down a plugin. I assume that you’re aware of the fabric in that submit.

This submit is analogous to Programming an estimation command in Stata: Writing a C plugin. The variations are as a result of plugin code being in C++ as a substitute of C. I don’t assume that you’re aware of the fabric in that submit, and you’ll discover a lot of it repeated right here.

That is the thirty first submit within the collection Programming an estimation command in Stata. I like to recommend that you simply begin at first. See Programming an estimation command in Stata: A map to posted entries for a map to all of the posts on this collection.

Writing a hello-world C++ plugin

Earlier than I do any computations, I illustrate tips on how to write and compile a C++ plugin that communicates with Stata. Code block 1 incorporates the code for myhellocpp.ado that calls the C++ plugin hellocpp, which simply shows “Howdy from C++” in Stata.

Code block 1: myhellocpp.ado


*! model 1.0.0  13Feb2018
program outline myhellocpp

    model 15.1

    plugin name hellocpp

finish

program hellocpp, plugin

Line 6 executes the plugin whose deal with is hellocpp. Line 10 masses the plugin carried out in hellocpp.plugin into the deal with hellocpp. That the execute assertion comes earlier than the load assertion appears odd at first. Stata ado-files are learn of their entirety, and every ado-program, Mata perform, or plugin deal with is loaded earlier than the strains of the primary ado-program are executed. So line 10 is definitely executed earlier than line 6.

The identify of the deal with for the plugin, hellocpp on this case, should differ from the identify of the primary ado-program, myhellocpp on this case, and from some other ado-program outlined on this .ado file.

The code for good day.cpp is in code block 2.

Code block 2: good day.cpp


// model 1.0.0 14Feb2018
#embody "stplugin.h"
#embody 
#embody 

STDLL stata_call(int argc, char *argv[])
{
    char  msg[81] ;

    std::string mystring = "Howdy from C++n";
    strcpy(msg, mystring.c_str()) ;
    SF_display(msg) ;

    return((ST_retcode) 0) ;
}

Line 2 consists of the Stata plugin header file stplugin.h. Line 6 is the usual declaration for the entry perform for a C++ plugin for Stata. It’s best to copy it. Inside stata_call(), argc will comprise the variety of arguments handed to the plugin, and string vector argv will comprise the arguments themselves.

Line 8 declares and allocates area for the C++ character array msg. Utilizing a personality array may appear odd, as a result of C++ packages usually use C++ strings to control strings. We’ll want character arrays as a result of capabilities within the Stata program interface (SPI) that settle for “string” arguments use C/C++ character arrays.

For instance, on line 12, the SPI perform SF_display(), which makes Stata show “Howdy from C++”, accepted the C++ character array msg. SF_display() wouldn’t settle for the C++ string mystring, created on line 10. Because of this, I copied what C++ mystring incorporates into the character array msg on line 11.

Line 14 returns zero because the return code. Be aware that I casted the literal 0 to be the anticipated kind ST_retcode.

I now talk about tips on how to create the plugin hellocpp.plugin from good day.cpp. Within the listing that incorporates myhellocpp.ado and good day.cpp, I even have stplugin.cpp. stplugin.cpp is a replica of stplugin.c. I needed to copy stplugin.c to stplugin.cpp as a result of some C++ compilers don’t deal with .c information as C++ supply information. stplugin.c defines a perform wanted to make the stata_call() perform accessible to Stata.

Don’t change the contents of stplugin.h or stplugin.c. In reality, you don’t even want to have a look at them.

On my OS X Mac that has the command-line developer instruments put in, I take advantage of g++ to create hellocpp.plugin from stplugin.cpp and good day.cpp by typing

g++ -bundle -DSYSTEM=APPLEMAC stplugin.cpp good day.cpp -o hellocpp.plugin

The above g++ command compiles the 2 .cpp information and hyperlinks them to create the DLL hellocpp.plugin, which myhellocpp.ado can name.

Within the appendix to this submit, I present directions for creating hellocpp.plugin on different platforms. https://www.stata.com/plugins/ offers full documentation for writing and compiling C++ plugins.

Having created hellocpp.plugin, I can execute myhellocpp in Stata.

Instance 2: myhellocpp


. myhellocpp
Howdy from C++

For simplicity, I’ve stplugin.h, stplugin.cpp, good day.cpp, myhellocpp.ado, and hellocpp.plugin in the identical listing. For bigger initiatives, I’d put the .ado and .plugin information in directories on Stata’s ADOPATH and use my compiler’s atmosphere to handle the place I put my header and C++ supply information. For the examples on this submit, I put all my .ado information, header information, C++ supply information, and created .plugin information right into a single listing.

Gaining access to the Stata information in your plugin

hellocpp.plugin makes Stata show one thing created contained in the plugin. The subsequent step is giving the plugin entry to the info in Stata. For example this course of, I talk about mylistcpp.ado, which makes use of a plugin to record out observations of the required variables.

Let’s have a look at the ado-code first.

Code block 3: mylistcpp.ado


*! model 1.0.0  13Feb2018
program outline mylistcpp, eclass

        model 15.1

        syntax varlist(numeric max=3) [if] [in]
        marksample touse

        show "Variables listed:  `varlist'"
        plugin name mylistwcpp `varlist' if `touse' `in'

finish

program mylistwcpp, plugin

In line 6, syntax creates three native macros. It places the variables specified by the consumer into the native macro varlist. It places any if situation specified by the consumer into the native macro if. It places any in vary specified by the consumer into the native macro in. I specified max=3 to syntax to restrict the variety of variables to three. This limitation is foolish, and I’d not want it for an instance Stata/Mata program, however it simplifies the instance C++ plugin.

In line 7, marksample creates a sample-inclusion variable and places its identify within the native macro touse. The sample-inclusion variable is zero for every excluded remark, and it’s one for every included remark. marksample makes use of the variables within the native macro varlist, the if situation within the native macro if, and the vary within the native macro in to create the sample-inclusion variable. (All three native macros had been created by syntax.) An remark is excluded if any of the variables within the native macro varlist comprise a lacking worth, if it was excluded by the situation within the native macro if, or if it was excluded by the vary within the native macro in. The sample-inclusion variable is one for observations that weren’t excluded.

In line 9, I additional simplified the C++ plugin by displaying the names of the variables whose values are listed out by the plugin.

In line 10, plugin calls mylistwcpp.plugin. As a result of `varlist’ is specified, the SPI perform SF_vdata() will be capable to entry the variables contained within the native macro varlist. As a result of if `touse’ is specified, the SPI perform SF_ifobs() will return zero if the sample-inclusion variable in touse is zero, and the perform will return one if the sample-inclusion variable is one. As a result of `in’ is specified, the SPI capabilities SF_in1() and SF_in2() respectively return the primary and final observations in any user-specified in vary.

Specifying `in’ just isn’t essential to determine the pattern specified by the consumer, as a result of if `touse’ already specifies this sample-inclusion info. Nonetheless, specifying `in’ can dramatically cut back the vary of observations within the loop over the info, thereby dashing up the code.

In a listing that incorporates mylistw.cpp, stplugin.cpp, and stplugin.h, I created mylistwcpp.plugin on my Mac by typing

g++ -bundle -DSYSTEM=APPLEMAC stplugin.cpp mylistw.cpp -o mylistwcpp.plugin

Code block 4: mylistw.cpp


// model 1.0.0  14Feb2018
#embody "stplugin.h"
#embody 
#embody 
#embody 
#embody 

STDLL stata_call(int argc, char *argv[])
{
    ST_int       first, final, nVars, i, j, nObs  ;
    ST_double    worth ;
    ST_retcode   rc ;
    int          nchar ;
    char         line[81], msg[81], svalue[26] ;
    std::string  line2 ;

    rc    = (ST_retcode) 0 ;
// Put the primary remark in pattern into first
    first = SF_in1 ();
// Put the final remark in pattern into final
    final = SF_in2 ();
// Put variety of variables in varlist handed in to plugin into nVars
    nVars  = SF_nvars() ;
// Provoke variety of observations counter to 0
    nObs  = 0 ;

// Loop over observations
    for(i=first; i<=final; i++) {
        line2 = "";
// Solely show observations for which if restriction is true
        if (!SF_ifobs(i)) {
            proceed ;
        }
// Increment variety of observations counter
        ++nObs ;
// Loop over variables
        for(j=1; j<=nVars; j++) {
// Put worth of remark i on variable j into worth 
            rc = SF_vdata(j, i, &worth);
// Return with error if downside getting worth
            if(rc>0) {
                 sprintf(msg, "Downside accessing Stata datan") ;
                 SF_error(msg) ;
                 return(rc) ;
            }
// Return with error if lacking worth
            if (SF_is_missing(worth)) {
                 sprintf(msg, "lacking values encounteredn") ;
                 SF_error(msg) ;
                 return( (ST_retcode) 416 ) ;
            }
            snprintf(svalue,25,"%f   ",worth) ;
            line2 = line2 + svalue ;
        }
// Show line or error message in Stata
        if (line2.size()<=80) {
            line2 = line2 + "n" ;
            strcpy(line, line2.c_str()) ;
            SF_display(line) ;
        }
        else {
             sprintf(msg, "Greater than 80 bytes in linen") ;
             SF_error(msg) ;
             return( (ST_retcode) 498 ) ;
        }
    }
    sprintf(line, "First remark was             %dn", first) ;
    SF_display(line) ;
    sprintf(line, "Final remark was              %dn", final) ;
    SF_display(line) ;
    sprintf(line, "Variety of observations listed was %dn", nObs) ;
    SF_display(line) ;

    return(rc) ;
}

In case you are studying this submit, you may learn normal C++. I talk about how mylistw.cpp illustrates the construction of C++ plugins for Stata, and I clarify the kinds and the capabilities outlined by the Stata plugin interface (SPI) used within the code. Full particulars concerning the SPI can be found at https://www.stata.com/plugins/.

mylistw.cpp returns zero to Stata if all went effectively, and it returns a nonzero error code if one thing went flawed. Each time I name a perform in mylistw.cpp that might fail, I verify its return code. If that perform failed, I make Stata show an error message, and I return a nonzero error code to Stata. This logic offers the general construction to mylisw.cpp. Many of the code offers with error situations or takes care to not put extra characters right into a string buffer than it will possibly maintain.

C++ plugins learn from or write to Stata objects utilizing capabilities outlined within the SPI. mylistw.cpp doesn’t return any outcomes, so it has a easy construction.

  • It makes use of SPI capabilities to learn from the required pattern of the info in Stata.
  • It makes use of normal C++ and SPI capabilities to record observations for the required, pattern and it retains a counter of what number of observations are within the specified pattern.
  • It makes use of normal C++ and SPI capabilities to show which was the primary remark within the pattern, which was the final remark within the pattern, and what number of observations had been within the specified pattern.

Now, I talk about particular elements of mylistw.cpp.

In strains 10–12, I take advantage of the SPI outlined varieties ST_int, ST_double, and ST_retcode for variables that the SPI capabilities return or which can be arguments to the Stata plugin interface capabilities. Utilizing these outlined varieties is important, as a result of their mappings to primitive C++ varieties differ over time.

rc holds the return code that the plugin will return to Stata. In line 17, I initialize rc to zero. If an SPI perform which may fail does what was requested, it returns a return code of zero. If an SPI perform can not do what was requested, it returns a nonzero return code. Every time I name an SPI perform which may fail, I retailer the code it returns in rc. If rc just isn’t zero, I make Stata show an error message and make the plugin return the nonzero worth saved in rc.

Strains 19, 21, and 23 use SPI capabilities. SF_in1() places the primary remark specified by an in vary into first. SF_in2() places the final remark specified by an in vary into final. If an in vary was not specified to plugin, first will comprise one, and final will comprise the variety of observations within the dataset. SF_nvars() places the variety of variables specified within the varlist into nVars.

Strains 31–33 be certain that we skip over observations that had been excluded by the if restriction specified to plugin in line 10 of mylistcpp.ado. For example some particulars, take into account instance 2.

Instance 2: mylistcpp


. sysuse auto, clear
(1978 Car Information)

. mylistcpp mpg trunk rep78 if trunk < 21 in 2/10
Variables listed:  mpg trunk rep78
17.000000   11.000000   3.000000
20.000000   16.000000   3.000000
15.000000   20.000000   4.000000
20.000000   16.000000   3.000000
16.000000   17.000000   3.000000
19.000000   13.000000   3.000000
First remark was             2
Final remark was              10
Variety of observations listed was 6

In line 31, SF_ifobs(i) returns one when the if restriction specified to plugin is one for remark i, and nil in any other case. In line 10 of mylistcpp.ado, we see that the if restriction handed to plugin is if `touse’. As mentioned above, the sample-inclusion variable within the native macro touse is zero for excluded observations, and it’s one for the included observations.

The in vary on line 10 of mylistcpp.ado was included in order that the loop over the observations in line 28 of mylistw.cpp would solely go from the start to the top of any specified in vary. In instance 2, as a substitute of looping over all 74 observations within the auto dataset, the loop on line 28 of mylistw.cpp solely goes from 2 to 10.

In instance 2, the sample-inclusion variable is 1 for six observations, and it’s 0 for the opposite 68 observations. The in 2/10 vary excludes remark 1 and the observations from 11–74. Of the primary 10 observations, 2 are excluded as a result of rep78 is lacking. One remark is excluded as a result of trunk is 21.

For comparability, all 9 observations between 2 and 10 are listed in instance 3.

Instance 3: record


. record mpg trunk rep78 in 2/10

     +---------------------+
     | mpg   trunk   rep78 |
     |---------------------|
  2. |  17      11       3 |
  3. |  22      12       . |
  4. |  20      16       3 |
  5. |  15      20       4 |
  6. |  18      21       3 |
     |---------------------|
  7. |  26      10       . |
  8. |  20      16       3 |
  9. |  16      17       3 |
 10. |  19      13       3 |
     +---------------------+

Returning to line 39 of mylistw.c, rc_st = SF_vdata(j, i, &worth) places the worth of remark i on variable j into worth, and it places the code returned by SF_vdata() into rc. If all goes effectively, rc incorporates 0, and the error block in strains 42–44 just isn’t entered. If SF_vdata() can not retailer the info into worth, the error block in strains 42–44 is entered. The error block makes Stata show an error message, and it causes mylistw.plugin to exit with the error code that rc incorporates. Within the error block, SF_error() makes Stata show the contents of a C++ character array in pink.

SF_vdata() can solely entry variables of one of many numerical Stata information varieties (byte, int, lengthy, float, or double). (Use SF_sdata() for string information.) No matter which Stata numerical kind the variable is, SF_vdata() shops the consequence as an ST_double. In instance 2, mpg, trunk, rep78 are all of kind int in Stata, however every was saved into worth as an ST_double.

In line 47, SF_is_missing(worth) returns 1 if worth is a lacking worth, and it returns 0 in any other case. Strains 47–51 trigger mlistw.plugin to exit with error 416 if any remark in one of many variables incorporates a lacking worth. These strains are redundant, as a result of the sample-inclusion variable handed to mylistw.plugin excluded observations containing lacking values. I included these strains for instance how I’d safely exclude lacking values from contained in the plugin and to reiterate that C++ code should rigorously cope with lacking values. Stata lacking values are legitimate double precision numbers in C++. You’ll get flawed outcomes should you embody Stata lacking values in calculations.

The remaining strains assemble the C++ character array line that’s handed to Stata to show every remark, and so they show the abstract details about the pattern.

Estimating the imply in a C++ plugin

I now talk about the ado-command mymeancpp that makes use of mycalcscpp.plugin to implement the calculations carried out by mymean_work() in mymean11.ado, mentioned in Programming an estimation command in Stata: Making ready to jot down a plugin.

The code for mymeancpp is in mymeancpp.ado, which is in code block 5.

Code block 5: mymeancpp.ado


*! model 1.0.0  13Feb2018
program outline mymeancpp, eclass

        model 15.1

        syntax varlist(numeric) [if] [in]
        marksample touse
        tempname b V N

        native okay : phrase depend `varlist'
        matrix `b' = J(1, `okay', .)
        matrix `V' = J(`okay', `okay', .)

        plugin name mycalcscpp `varlist' if `touse' `in', `b' `V' `N'

        matrix colnames `b'  = `varlist'
        matrix colnames `V'  = `varlist'
        matrix rownames `V'  = `varlist'
        ereturn submit `b' `V', esample(`touse')
        ereturn scalar   N   = `N'
        ereturn scalar df_r  = `N'-1
        ereturn show

finish

program mycalcscpp, plugin

The final construction of this program is identical as mymean10.ado and mymean11, mentioned in Programming an estimation command in Stata: Making ready to jot down a plugin. From a fowl’s-eye view, mymeancpp.ado

  • parses the consumer enter;
  • creates some names and objects to carry the outcomes;
  • calls a piece program to do the calculations;
  • shops the outcomes returned by the work program in e(); and
  • shows the outcomes.

The principle distinction between mymeancpp.ado and mymean11.ado is that the work program is a C++ plugin as a substitute of a Mata perform.

Strains 6 and seven are equivalent to these in mylistcpp.ado. For an outline of how these strains create the native macro varlist, the sample-inclusion variable contained within the native macro touse, and the native macro in that incorporates any user-specified in vary, see the dialogue of mylistcpp.ado in Gaining access to the Stata information in your plugin.

Line 8 places momentary names into the native macros b, V, and N. We use these names for outcomes computed by the C++ plugin, and we all know that we’ll not overwrite any outcomes {that a} consumer has saved in world Stata reminiscence. (Recall that Stata matrices and scalars are world objects in Stata; see Utilizing momentary names for world objects in Programming an estimation command in Stata: A primary ado-command for a dialogue of this subject.) As well as, Stata will drop the objects within the momentary names created by tempname, when mymeancpp terminates.

Strains 10–12 create Stata matrices to carry the outcomes. We use the momentary names created by tempname for these matrices.

Line 14 in mymeancpp is just like its counterpart of line 10 in mylistcpp.ado. On this case, plugin calls mycalcspp.plugin to do the work. The small print of varlist, if `touse’, and `in’
had been mentioned above. What’s new is that we cross the arguments `b’ `V’ `N’ to cross the momentary names to mycalcs.plugin.

mycalcscpp.plugin

  • does the calculations;
  • places the estimated means into the Stata matrix whose identify is within the native macro b;
  • places the VCE into the Stata matrix whose identify is within the native macro V; and
  • places the variety of observations within the pattern into the Stata scalar whose identify is within the native macro N.

Strains 16–18 put the variable names on the column stripe of the vector of estimated means and on the row and column stripes of the VCE matrix. Strains 19–21 retailer the leads to e(). Line 22 shows the outcomes.

I now talk about the code that creates mycalcs.plugin. Earlier than discussing particulars, let’s create the plugin and run an instance.

In a listing that incorporates mycalcs.cpp, mymatrix.cpp, mycalcsv.cpp, mymatrix.h, mycalcsv.h, stplugin.cpp, and stplugin.h, I created mycalcscpp.plugin on my Mac by typing

g++ -bundle -DSYSTEM=APPLEMAC mycalcs.cpp mymatrix.cpp mycalcsv.cpp stplugin.cpp -o mycalcscpp.plugin

Having created mycalcscpp.plugin, I ran instance 3.

Instance 3: mymeancpp


. mymeancpp mpg trunk rep78 in 1/60
------------------------------------------------------------------------------
             |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
         mpg |     20.125   .6659933    30.22   0.000     18.79032    21.45968
       trunk |   14.42857   .5969931    24.17   0.000     13.23217    15.62497
       rep78 |   3.160714    .118915    26.58   0.000     2.922403    3.399025
------------------------------------------------------------------------------

I now talk about some elements of the C++ code used to create mycalcscpp.plugin. I start with mycalcs.cpp in code block 6, which incorporates the code for the entry perform stata_call().

Code block 6: mycalcs.cpp


// model 1.0.0 14Feb2018
// C++ mycalcs plugin for Stata
#embody "stplugin.h"
#embody 
#embody 
#embody 
#embody 
#embody "mymatrix.h"
#embody "mycalcsv.h"

//Unicode characters could make stata names as much as 32*4+1=129 bytes
STDLL stata_call(int argc, char *argv[])
{
    ST_int       first, final, nvars, nobs ;
    ST_int       i  ;
    ST_retcode   rc ;
    char         bname[130], vname[130], nname[130], msg[81] ;

    rc = static_cast(0) ;

// Examine that arguments aren't too lengthy for buffers
    for(i=0; i<3; i++) {
       if (strlen(argv[i])>129) {
            sprintf(msg, "Argument %d is greater than 129 bytes longn",i+1);
            SF_error(msg) ;
            return(static_cast(198)) ;
       }
    }
// Retailer arguments into strings 
// NB: No extra checking required
//     capabilities will return nonzero codes if arguments specify unhealthy names
    strcpy(bname,argv[0]) ;
    strcpy(vname,argv[1]) ;
    strcpy(nname,argv[2]) ;

    nvars = SF_nvars() ;
    first = SF_in1();
    final  = SF_in2();

// Create bmat to carry vector of pattern averages
    MyMatrix bmat(1, nvars) ;
// Create vmat to carry VCE
    MyMatrix vmat(nvars, nvars) ;

// Put pattern averages into bmat and # of obs in nobs
    rc = MyAve(bmat, first, final, nvars, &nobs) ;
    if(rc>0) return(rc) ;
// Put VCE into vmat and # of obs in n
    rc = MyV(bmat, vmat, first, final, nvars, nobs) ;
    if(rc>0) return(rc) ;

// Copy pattern averages from bmat to Stata matrix bname
    rc = bmat.CopyCtoStataMatrix(bname)  ;
    if(rc>0) return(rc) ;

// Copy VCE from vmat to Stat matrix vname
    rc = vmat.CopyCtoStataMatrix(vname)  ;
    if(rc>0) return(rc) ;

// Copy variety of obs from n to nname
    rc = SF_scal_save(nname, (ST_double) nobs);
    if(rc>0) return(rc) ;

    return(rc) ;
}

In abstract, the code in mycalcs.cpp performs the next duties.

  1. It places the names of Stata objects handed in as arguments into C++ character arrays that may be handed to SPI capabilities.
  2. It creates the bmat and vmat situations of the MyMatrix class, which is able to maintain outcomes.
  3. It makes use of the work capabilities MyAve() and MyV() to compute the outcomes which can be saved in bmat, vmat, and nobs.
  4. It makes use of the member perform CopyCtoStataMatrix() of the MyMatrix class and the SPI perform SF_scal_save() to repeat the outcomes from bmat, vmat, and nobs to the Stata objects whose names had been parsed in step 1.

mycalcs.cpp is straightforward to learn, as a result of I put all the small print into the MyMatrix class and into work capabilities. The MyMatrix class is outlined in mymatrix.cpp, and the work capabilities are outlined in mycalcsv.cpp, which I talk about under.

Like mylistw.cpp, mycalcs.cpp makes use of the return code rc to deal with error situations. Every perform returns zero if all went effectively, and every perform returns a nonzero error code if it couldn’t carry out the requested job. If the code returned just isn’t zero, mycalcs.cpp returns it instantly to stata_call(), which in flip returns the nonzero code to Stata. The error messages related to the error situations are displayed by the work capabilities.

In level (2), I famous that bmat and vmat are situations of the MyMatrix class. The pattern averages and the VCE are greatest saved in matrices. To maintain issues easy and self-contained, I outlined a bare-bones matrix class MyMatrix that makes use of row-major storage and solely the member capabilities I wanted. Aside from the member perform copyCtoStataMatrix(), the code for MyMatrix is normal C++, as will be seen in code block 7.

Code block 7: mymatrix.cpp


// model 1.0.0  14Feb2018
// supply file for MyMatrix class
#embody 
#embody 
#embody "mymatrix.h"
#embody "stplugin.h"

#outline M(i,j)  *(mat+(i)*c+j) 

// Constructor
//   creates matrix and and initializes parts to zero 
// Notes: matrices are lengthy vectors with row-major storage
//    The i,j factor of an r x c matrix is 
//    the (i-1)*r + (j-1) factor of the of the vector
//    underneath C-style zero-base indexing
//
MyMatrix::MyMatrix(ST_int rows, ST_int cols) : r(rows), c(cols)
{
    ST_int i, j, TotalSize ;

    TotalSize = r * c ;
    attempt {
        mat = new ST_double[TotalSize];
        for(i=0; i0) {
                sprintf(msg, "can not entry Stata matrix %sn", smname) ;
                SF_error(msg) ;
                return(rc_st) ;
            }
        }
    }
    return(rc_st) ;
}

#undef M

On line 8, I used a preprocessor macro to simplify the code that refers to a component of a matrix. I undefine the macro on line 79.

Strains 57–77 comprise the code for CopyCtoStataMatrix(). Line 68 makes use of an SPI perform that I’ve not but mentioned. SF_mat_store(char *sname, ST_int i, ST_int j, ST_double val) shops the worth val in row i and column j of the Stata matrix whose identify is contained in character array sname. The row i and column j are given in one-based indexing.

Line 67 makes use of the member perform GetValue(i,j), which returns the (i,j) factor of the matrix in an occasion of the MyMatrix class. GetValue() is outlined in mymatrix.h, which is the header file that incorporates the declaration for the MyMatrix class. Code block 8 incorporates the code in mymatrix.h.

Code block 8: mymatrix.h


// model 1.0.0  14Feb2018
// header file for MyMatrix class
#embody "stplugin.h"

#outline M(i,j)  *(mat+(i)*c+j) 

class MyMatrix {
personal:
        ST_int    r, c;
        ST_double *mat ;
        ST_int    TotalSize ;

public:
        ST_retcode  rc ;
// constructor
        MyMatrix(ST_int rows, ST_int cols) ;
// destructor
        ~MyMatrix() ;
// Return (i,j)th factor 
        inline ST_double GetValue(ST_int i, ST_int j) {
                return( M(i,j) ) ;
        }
// Retailer val into (i,j)th factor 
        inline void StoreValue(ST_int i, ST_int j, ST_double val) {
                M(i,j) = val ;
        }
// Increment (i,j)th factor  by val
        inline void IncrementByValue(ST_int i, ST_int j, ST_double val) {
                M(i,j) += val ;
        }
// Divide every factor by val
        void DivideByScalar(ST_double val) ;
// Copy from class to Stata matrix smname
        ST_retcode CopyCtoStataMatrix(char *smname) ;
// Return rows of matrix
        inline ST_int Rows() { return r; }
// Return cols of matrix
        inline ST_int Cols() { return c ; }
};

#undef M

This code solely makes use of normal C++ and coding strategies that I’ve already mentioned.

In level (3), I famous that mycalcs.cpp makes use of the work capabilities MyAve() and MyV() to compute the outcomes. These capabilities are outlined in mycalcsv.cpp in code block 9.

Code block 9: mycalcsv.cpp


// model 1.0.0  14Feb2018
// Features utilized in mycalcs.cpp
//
#embody 
#embody "stplugin.h"
#embody "mymatrix.h"
#embody "mycalcsv.h"

ST_retcode MyAve(MyMatrix &bmat, ST_int first, ST_int final,
    ST_int nvars, ST_int *nobs)
{
    ST_int     i, j ;
    ST_double  worth ;
    ST_retcode rc ;
    char       msg[80] ;

    *nobs = (ST_int) 0 ;
    for(i=first-1; i0) {
                sprintf(msg, "Downside accessing Stata datan") ;
                SF_error(msg) ;
                return(rc) ;
            }
            if (SF_is_missing(worth)) {
                sprintf(msg, "lacking values encounteredn") ;
                SF_error(msg) ;
                return(static_cast(416)) ;
            }
            bmat.IncrementByValue(0, j, worth) ;
        }
    }

    bmat.DivideByScalar( static_cast(*nobs) ) ;
    return(rc) ;
}

ST_retcode MyV(MyMatrix &bmat, MyMatrix &vmat, ST_int first,
    ST_int final, ST_int nvars, ST_int nobs)
{

    ST_int      i, j, j2 ;
    ST_double  worth ;
    char       msg[80] ;
    ST_retcode rc ;

    rc = (ST_retcode) 0 ;
    MyMatrix emat2(1, nvars) ;

    for(i=first-1; i0) {
                sprintf(msg, "Downside accessing Stata datan") ;
                SF_error(msg) ;
                return(rc) ;
            }
            if (SF_is_missing(worth)) {
                sprintf(msg, "lacking values encounteredn") ;
                SF_error(msg) ;
                return(static_cast(416)) ;
            }
            emat2.StoreValue(0, j, (bmat.GetValue(0,j)-value) ) ;
        }
        for(j=0; j (nobs*(nobs-1))) ) ;

    return(rc) ;
}

The work perform MyAve() is a C++ implementation of the MyAve() carried out in Mata in Programming an estimation command in Stata: Making ready to jot down a plugin. It places the pattern averages into the bmat occasion of the MyMatrix class, and it places the variety of observations within the pattern into nobs. Many of the code for this perform is normal C++ or it makes use of SPI capabilities that I’ve already mentioned. Strains 35 and 39 deserve remark.

Line 35 makes use of the IncrementByValue() member perform of MyMatrix. When calculating the pattern common and storing it within the jth factor of a vector named b, one must retailer b[j] + worth into b[j]. In different phrases, one increments the quantity of the jth factor in b by worth. bmat.IncrementByValue(0,j, worth) increments factor j in bmat by worth.

Line 39 makes use of the DivideByScalar() member perform of MyMatrix. bmat.DivideByScalar(z) replaces every factor of bmat with that factor divided by the quantity z.

MyV() is a C++ implementation of the Mata perform MyV() mentioned in Programming an estimation command in Stata: Making ready to jot down a plugin. It places the VCE into the vmat occasion of the MyMatrix class. Many of the code for this perform is both normal C++, or makes use of strategies that I’ve already mentioned. Strains 71, 78, and 87 use the MyMatrix member capabilities Storevalue() and GetValue(), that are outlined in mymatrix.h. vmat.StoreValue(i, j, z) shops the worth z into factor (i, j) of the vmat occasion of MyMatrix. vmat.GetValue(i, j) returns the worth saved in factor (i, j) of the vmat occasion of MyMatrix.

Executed and undone

I confirmed tips on how to implement a C++ plugin that does the calculations carried out by Mata work capabilities in mymean10.ado and mymean11.ado, as mentioned in Programming an estimation command in Stata: Making ready to jot down a plugin. Within the subsequent submit, I present tips on how to implement these calculations in a Java plugin.

Appendix

Within the textual content, I confirmed tips on how to compile and hyperlink a plugin on an OS 10 Mac utilizing the command-line developer instruments. Right here I give the instructions for the gcc compiler on Home windows 10 and on RedHat Linux.

Home windows 10

This subsection offers the instructions to compile and hyperlink the plugins in a Cygwin atmosphere on a 64-bit Home windows 10 system. Not like the opposite platforms, we can not simply use gcc. In Cygwin, gcc compiles purposes to run within the Cygwin POSIX/Unix atmosphere. We need to use Cygwin to compile a library that may hyperlink to, and run in, a local Home windows utility. Cygwin has minimalist GNU compilers for Home windows (MinGW) that may do what we wish. The identify of the suitable compiler is platform dependent. On my 64-bit, x86-Intel machine, I used the x86_64-w64-mingw32-g++ compiler.

hellocpp.plugin

In a listing containing stplugin.h, stplugin.cpp, and good day.cpp, create hellocpp.plugin by typing

x86_64-w64-mingw32-g++ -shared -static stplugin.cpp good day.cpp -o hellocpp.plugin

mylistwcpp.plugin

In a listing that incorporates stplugin.h, stplugin.cpp, and mylistw.cpp, create mylistwcpp.plugin by typing

x86_64-w64-mingw32-g++ -shared -static stplugin.cpp mylistw.cpp -o mylistwcpp.plugin

mycalcscpp.plugin

In a listing that incorporates stplugin.cpp, stplugin.h, mycalcs.cpp, mycalcsv.h, and mycalcsv.cpp, create mycalcscpp.plugin by typing

x86_64-w64-mingw32-g++ -shared -static stplugin.cpp mycalcsv.cpp mycalcs.cpp -o mycalcscpp.plugin

RedHat Linux

This subsection offers the gcc instructions to compile and hyperlink plugins on RedHat Linux.

hellocpp.plugin

In a listing containing stplugin.h, stplugin.cpp, and good day.cpp, create hellocpp.plugin by typing

g++ -shared -fPIC -DSYSTEM=OPUNIX stplugin.cpp good day.cpp -o hellocpp.plugin

mylistwcpp.plugin

In a listing that incorporates stplugin.h, stplugin.cpp, and mylistw.cpp, create mylistwcpp.plugin by typing

g++ -shared -fPIC -DSYSTEM=OPUNIX stplugin.cpp mylistw.cpp -o mylistwcpp.plugin

mycalcscpp.plugin

In a listing that incorporates stplugin.cpp, stplugin.h, mymatrix.cpp, mycalcsv.cpp, mycalcs.cpp, mymatrix.h, and mycalcsv.h, create mycalcscpp.plugin by typing

g++ -shared -fPIC -DSYSTEM=OPUNIX stplugin.cpp mymatrix.cpp mycalcsv.cpp mycalcs.cpp -o mycalcscpp.plugin



Related Articles

Latest Articles