Announcement

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

  • How to tranfer a temporary variable from one ado to another

    I have two ados: Ado1 for an estimation command calling Ado2 in ml model, and Ado2 for the estimation algorithm. How can I transfer a temporary variable created in Ado1 to Ado2? Below is a simplified example:
    Code:
    program Ado1
    syntax varlist [if] [in]
    gettoken y rhs : varlist
    tempvar TV
    gen `TV'=_n
    ml model lf Ado2 (`y' = `rhs') () `if' `in', `vce'
    ml max
    end
    
    program Ado2
    args lnf mu lnsigma
    summ `TV'
    quietly replace `lnf' = ln(normalden($ML_y1, `mu', exp(`lnsigma')))
    end

  • #2

    Code:
    program Ado1
    syntax varlist [if] [in]
    gettoken y rhs : varlist
    tempvar TV
    gen `TV'=_n
    ml model lf Ado2 (`y' `TV'= `rhs') () `if' `in', `vce'
    ml max
    end
    
    program Ado2
    args lnf mu lnsigma
    summ $ML_y2
    quietly replace `lnf' = ln(normalden($ML_y1, `mu', exp(`lnsigma')))
    end

    Comment


    • #3
      But making the temporary variable TV equal to $ML_y2 makes it an equation to be evaluated in ML, no? TV should not be evaluated. Is there a way to pass the temporary variable from Ado1 to Ado2 without making it a part of ML evaluation?
      Last edited by Cyrus Levy; 03 Mar 2020, 21:05.

      Comment


      • #4
        It will not be evaluated, unless you add it as an explanatory variable.
        Try it on and you will see

        Comment


        • #5
          I actually just tried what you suggest, and it did not work. `TV' = `rhs' becomes an equation that ML tries to fit, and that messes with the likelihood estimation. TV becomes a dependent variable in your example. I don't want that.

          Comment


          • #6
            You might have to resort to passing the variable name via a global macro. Try something like
            Code:
            clear *
            
            quietly sysuse auto
            
            program define sendem
            
                tempvar TV
                quietly generate byte `TV' = _n
            
                global temporary_variable `TV'
            
                getem
            
            end
            
            
            program define getem
            
                summarize $temporary_variable
            
            end
            
            sendem
            
            exit
            Maybe using a Mata function as the evaluator will provide the flexibility that you're looking for, I don't know, but you might want to look into that as an alternative to a global macro.

            Comment


            • #7
              There is a stata tip on this: https://www.stata-journal.com/articl...article=pr0061
              ---------------------------------
              Maarten L. Buis
              University of Konstanz
              Department of history and sociology
              box 40
              78457 Konstanz
              Germany
              http://www.maartenbuis.nl
              ---------------------------------

              Comment


              • #8
                Originally posted by Maarten Buis View Post
                Maarten, I was aware of one of your older posts in 2014 and this tip that you mentioned. My case is slightly different, which causes the complication. The subprogram Ado2 is not directly called from Ado1. Instead, Ado2 is called inside the -ml model- command, which makes every argument that comes after Ado2 a part of the ML model. So even if you include args (or syntax in your example) in Ado2, they all become a part of ML to be evaluated. That is the problem here.

                What I am currently doing is what Joseph suggested above, but globals are not the solution, of course, since they linger around after the program completes or breaks.

                Comment


                • #9
                  Originally posted by Cyrus Levy View Post
                  but globals are not the solution, of course, since they linger around after the program completes or breaks.
                  I shun global macros, too, whenever I can. But you can control their duration with the commands available. See the example below, extended from that shown in #6 above.

                  .ÿ
                  .ÿversionÿ16.1

                  .ÿ
                  .ÿclearÿ*

                  .ÿ
                  .ÿquietlyÿsysuseÿauto

                  .ÿ
                  .ÿprogramÿdefineÿsendem
                  ÿÿ1.ÿÿÿÿÿÿÿÿÿversionÿ16.1
                  ÿÿ2.ÿÿÿÿÿÿÿÿÿsyntax
                  ÿÿ3.ÿ
                  .ÿÿÿÿÿtempvarÿTV
                  ÿÿ4.ÿÿÿÿÿquietlyÿgenerateÿbyteÿ`TV'ÿ=ÿ_n
                  ÿÿ5.ÿ
                  .ÿÿÿÿÿglobalÿtemporary_variableÿ`TV'
                  ÿÿ6.ÿ
                  .ÿÿÿÿÿgetem
                  ÿÿ7.ÿ
                  .ÿend

                  .ÿ
                  .ÿ
                  .ÿprogramÿdefineÿgetem
                  ÿÿ1.ÿÿÿÿÿÿÿÿÿversionÿ16.1
                  ÿÿ2.ÿÿÿÿÿÿÿÿÿsyntax
                  ÿÿ3.ÿ
                  .ÿÿÿÿÿsummarizeÿ$temporary_variable,ÿmeanonly
                  ÿÿ4.ÿÿÿÿÿÿÿÿÿdisplayÿinÿsmclÿasÿresultÿ"Nÿ=ÿ"ÿr(N)
                  ÿÿ5.ÿ
                  .ÿÿÿÿÿÿÿÿÿmacroÿdropÿtemporary_variableÿ//ÿ<=ÿthis
                  ÿÿ6.ÿ
                  .ÿend

                  .ÿ
                  .ÿsendem
                  Nÿ=ÿ74

                  .ÿ
                  .ÿcaptureÿnoisilyÿmacroÿlistÿtemporary_variable
                  globalÿmacroÿ$temporary_variableÿnotÿfound

                  .ÿ
                  .ÿexit

                  endÿofÿdo-file


                  .

                  Comment


                  • #10
                    Originally posted by Cyrus Levy View Post
                    [...] but globals are not the solution, of course, since they linger around after the program completes or breaks.
                    One way around that

                    Code:
                    program foo
                        version 15
                        
                        // make sure global is not defined
                        capture assert mi(`"$mname"')
                        if ( _rc ) {
                            display as err "global macro mname already defined"
                            exit 498
                        }
                        
                        nobreak {
                            global mname whatever
                            capture noisily break _foo `0'
                            local Rc = _rc
                            global mname // void
                        }
                        
                        exit `Rc'
                    end
                    
                    program _foo
                        code referring to $mname
                    end

                    Best
                    Daniel

                    Comment


                    • #11
                      Originally posted by Joseph Coveney View Post
                      I shun global macros, too, whenever I can. But you can control their duration with the commands available. See the example below, extended from that shown in #6 above.
                      Sure, if the program completes without a break, then the global can be dropped. But if the program gets interrupted by a user break, I think a workaround is needed such as what Daniel suggested above: Temporarily disabling the break until the global is dropped. Still, these solutions are not as elegant as tempvar and tempname. Making sure the global is not defined earlier by the user is one of the issues. Tempvar and tempname always get created. Additional code would be needed to make sure the global would get created for sure under a unique name that does not already exist in the system.

                      I still believe a simpler solution to my original problem should exist using tempvar and tempname. Any other ideas?

                      Comment


                      • #12
                        Originally posted by Cyrus Levy View Post
                        Any other ideas?
                        Whenever an indirectly called program is likely to need extra arguments passed to it, StataCorp typically has made provisions for that to happen via pass-through argument options to the intermediate program—see minbound for an example. StataCorp has implemented a wide variety of estimation commands using ml and as far as I can tell has not encountered such a pressing need for creating a temporary variable in the top program that needed to be passed through ml to the likelihood-evaluator program, and so has not made such a pass-through argument option available for ml. (Or if it has, then it seems to have relied on global macros, as for other variables involved in the estimation.)

                        It's not clear what you're trying to do with generating a temporary variable in the ml-calling program and passing the temporary variable's name around behind it to the likelihood-evaluator program, but whatever it is, maybe what you're doing can be handled in another way, perhaps by having the likelihood-evaluator program create the temporary variable, itself. The dataset wouldn't have changed in any fundamental way that would undermine this approach, would it?

                        Other alternatives are to explore using a Mata function for the likelihood evaluation and to look into directly working with ml's implementation in Mata where there might be more avenues to pass information between programmatic components.

                        Comment

                        Working...
                        X