Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • .ado Programming in Stata without invoking mata: Errors while passing arguments to function

    Level: Beginner
    Trying to write an .ado file. This is how it looks.

    When I was debugging this line by line, I am getting 2 errors.:
    1. xc, invalid name, r(198)
    2. y' invalid name, r(198)
    When I delete (`xc'==`k'), error #1 disappears and when I remove the extra " ' " after y in scalar asf = (`y''*ind), error #2 goes away. However, both the conditional check and finding the transpose of y are crucial to my code. How do I get rid of these errors?

    program func, rclass
    version 15.1

    syntax varlist(numeric min=4 max=4), i(integer) j(integer) k(integer)
    args y xa xb xc

    //indicator
    gen ind = (`xa' == `i')*(`xb' == `j')*(`xc'==`k')

    //some calculations
    qui sum ind, det
    scalar asf = (`y''*ind)

    return scalar asf = asf
    return scalar I = `i'
    return scalar J = `j'
    return scalar K = `k'

    drop
    ind

    end
    Last edited by Nilima Pisharody; 23 Mar 2019, 20:38.

  • #2
    You are being inconsistent by using both -syntax- and -args-, because the syntax that is appropriate for -syntax- does not work with -args-.

    -syntax- looks for a varlist, followed by a comma, and knows that the comma that follows it is not part of the varlist. By contrast -args- just looks for (in this case) 4 tokens. The result is that -args- interprets the comma that follows your xc as part of xc itself. When you then refer to `xc' it includes the comma, and that triggers an error.

    You also have a typo in the line -scalar asf = (`y''*ind)-: there should be only a single ' character after y.

    Finally, although you apparently haven't gotten that far, -dropind- is also a syntax error because a blank space is needed.

    Correcting these you code would look like this:
    Code:
    program func, rclass
    version 15.1
    
    syntax varlist(numeric min=4 max=4), i(integer) j(integer) k(integer)
    local y `:word 1 of `varlist''
    local xa `:word 2 of `varlist''
    local xb `:word 3 of `varlist''
    local xc `:word 4 of `varlist''
    
    //indicator
    gen ind = (`xa' == `i')*(`xb' == `j')*(`xc'==`k')
    
    //some calculations
    qui sum ind, det
    scalar asf = (`y'*ind)
    
    return scalar asf = asf
    return scalar I = `i'
    return scalar J = `j'
    return scalar K = `k'
    
    drop ind
    
    end

    There are other problems with this code, although they will not produce syntax errors.

    You summarize the variable ind (in detail!) yet you never make use of any of the results of that. Also the command -scalar asf = `y'*ind) will use only the value of ind from the very first observation in the data set to do the calculation. That's legal, but is it really what you want?

    As for
    However, both the conditional check and finding the transpose of y are crucial to my code.
    I don't get what you mean. What is the transpose of a variable?

    Perhaps if you explain what you are trying to calculate, more specific help can be given.

    Comment


    • #3
      I don't know how you got your first error. I don't see where a comma came from in your example. I recommend, though, following Clyde's advice in avoiding both syntax . . . and args . . . in the same program definition.

      Your second syntax error comes from the inability to use a variable name as you would the name of a Stata matrix (in this case a column vector) when you attempted your transpose operation. You have to first pull the contents of a variable into a Stata matrix via the mkmat command before you can transpose it. I think that you were trying something akin to this.
      Code:
      program define matfunc, rclass
          version 15.1
          syntax varlist(min=4 max=4), i(integer) j(integer) k(integer)
      
          foreach var of varlist `varlist' { // y xa xb xc
              local `var' `var'
          }
      
          tempname ind
          generate byte `ind' = `xa' == `i' & `xb' == `j' & `xc' == `k'
      
          // Here
          tempname Y I Asf
          mkmat `y', matrix(`Y')
          mkmat `ind', matrix(`I')
          matrix define `Asf' = `Y'' * `I'
          
          return scalar asf = `Asf'[1, 1]
      end
      Also, note that you need to return the product of Y' * I as a matrix; scalar define asf = Y' * I won't work even if both Y and I are Stata matrixes (column vectors).

      Regardless, if you want to avoid Mata and matrixes, then you can accomplish what you want without resorting to either, which is what I think you were after with your summarize line.
      Code:
      program define func, rclass
          version 15.1
          syntax varlist(min=4 max=4), i(integer) j(integer) k(integer)
      
          foreach var of varlist `varlist' { // y xa xb xc
              local `var' `var'
          }
      
          summarize `y' if `xa' == `i' & `xb' == `j' & `xc' == `k', meanonly
          return scalar asf = r(sum)
      end
      .ÿ
      .ÿversionÿ15.1

      .ÿ
      .ÿclearÿ*

      .ÿ
      .ÿsetÿseedÿ`=strreverse("1489739")'

      .ÿquietlyÿsetÿobsÿ3

      .ÿgenerateÿbyteÿyÿ=ÿruniformint(1,ÿ10)

      .ÿgenerateÿbyteÿaÿ=ÿmod(_n,ÿ2)

      .ÿgenerateÿbyteÿbÿ=ÿaÿ*ÿ2

      .ÿgenerateÿbyteÿcÿ=ÿaÿ*ÿ3

      .ÿrenameÿ(aÿbÿc)ÿx=

      .ÿ
      .ÿlist,ÿnoobs

      ÿÿ+------------------+
      ÿÿ|ÿyÿÿÿxaÿÿÿxbÿÿÿxcÿ|
      ÿÿ|------------------|
      ÿÿ|ÿ2ÿÿÿÿ1ÿÿÿÿ2ÿÿÿÿ3ÿ|
      ÿÿ|ÿ5ÿÿÿÿ0ÿÿÿÿ0ÿÿÿÿ0ÿ|
      ÿÿ|ÿ9ÿÿÿÿ1ÿÿÿÿ2ÿÿÿÿ3ÿ|
      ÿÿ+------------------+

      .ÿ
      .ÿquietlyÿprogramÿdefineÿmatfunc,ÿrclass

      .ÿ
      .ÿquietlyÿprogramÿdefineÿfunc,ÿrclass

      .ÿ
      .ÿmatfuncÿyÿxaÿxbÿxc,ÿi(1)ÿj(2)ÿk(3)

      .ÿreturnÿlist

      scalars:
      ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿr(asf)ÿ=ÿÿ11

      .ÿ
      .ÿfuncÿyÿxaÿxbÿxc,ÿi(1)ÿj(2)ÿk(3)

      .ÿreturnÿlist

      scalars:
      ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿr(asf)ÿ=ÿÿ11

      .ÿ
      .ÿexit

      endÿofÿdo-file


      .


      This, of course, is all guesswork, and if it's off-base, be sure to post back with clarification.

      Comment


      • #4
        Originally posted by Joseph Coveney View Post
        I don't see where a comma came from in your example.
        Got it. Never mind.

        Comment


        • #5
          Thank you for both your replies. That clarified a lot of Stata-programming concepts for me. And to answer both your question, yes, the program is meant to do more with the summarize command (more econometric calculations from the results of summarize) - but I chose to start with the simplest of '.ado program' and make it work. But I agree, it is a waste of programming space, and hence I am deleting it, for now. I have made the following changes (as in the code), but it gives me an error varlist required r(100);.


          Code:
          program stepone, rclass
              version 15.1
              syntax varlist(min=4 max=4), i(integer) j(integer) k(integer)
              foreach var of varlist `varlist' { // y xa xb xc
                 local `var' `var
              }
          
              gen byte ind = (`xa' == `i' & `xb' == `j' & `xc' == `k')
                  
              //calculations
          
              tempvar ydash idash asf
              mkmat `y', matrix(`ydash')
              mkmat `ind', matrix(`idash')
          
              matrix define `Asf' = (`ydash''*`idash')
              
              return scalar asf = `Asf'[1,1]
              drop ind
          end

          Comment


          • #6
            First, although they share the same (or at least overlapping) namespace, I recommend reserving tempvar for temporary variables and using tempname for temporary scalars and matrices. (I note that I accidentally used tempname for a temporary variable in #3 above.)

            Second, Stata is case-sensitive. So
            Code:
            tempname . . . asf
            won't provide for the same token that you tried to use later in
            Code:
            matrix define `Asf' = `ydash'' * `idash'
            So, change to:
            Code:
            tempname ydash idash Asf
            Third, your error message probably came from
            Code:
            mkmat `ind', matrix(`idash')
            Because you never defined `ind' as anything beforehand, it is empty (nothing, blank), and the line is rendered as if written
            Code:
            mkmat   , matrix(`idash')
            that is, a required argument (a variable name) is left blank. (You use a permanent variable's name for the indicator variable, and then manually dropped it at the end of the program definition.)

            Last, I used
            Code:
            foreach var of varlist `varlist' { // y xa xb xc
                local `var' `var
            }
            just for brevity in my illustration and don't recommend your using it, because it relies upon naming your variable exactly as shown in the comment. For flexibility in the names of the variables, I recommend using either what Clyde uses, or something like
            Code:
            gettoken y varlist : varlist
            gettoken xa varlist : varlist
            gettoken xb xc : varlist
            Actually, if it were me, I would forgo the variable list (the user might not put the variables in the correct order), and require that they be specified one-by-one as options.
            Code:
            help syntax##optional_varlist
            Last edited by Joseph Coveney; 25 Mar 2019, 02:24.

            Comment


            • #7
              Thank you, both of you! My basic indicator works.
              I used variable extraction as Clyde suggested and other tips from both of your replies!

              Comment

              Working...
              X