Announcement

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

  • "Already exists" issues on the Mata function of Stata program

    Dear Stata community,
    I'm making of stata program for my RA work.
    My final goal is to make this program as stata package like .ado file.

    So far, using Mata in my stata program, I finish coding up calculating desiring results.
    However, I am stuck on this "already exists" issue.

    First, right after running my .do file which includes the stata program and mata function, general commands for my program work well.
    However, after entering first command, the second and so forth command keep showing error message: "function_name" already exists.

    My code can be simplified as below:

    //////////////////////////////////////////////////////////////////
    capture program drop myprogram
    program myprogram
    version 13
    local a 3
    local b 5
    local mataend "end"
    di "`a'+`b'"

    mata:
    mata clear
    void myfunc(c,d){
    c+d
    }
    a = `a'
    b = `b'
    myfunc(a,b)
    `mataend'

    end
    //////////////////////////////////////////////////////////////////

    And the result is:

    //////////////////////////////////////////////////////////////////
    . do "C:\Users\Seongjin\myprogram.do"

    . program myprogram
    1. version 13
    2. local a 3
    3. local b 5
    4. di "`a'+`b'"
    5. local mataend "end"
    6.
    . mata:
    7. mata clear
    8. void myfunc(c,d){
    9. c+d
    10. }
    11. a = `a'
    12. b = `b'
    13. myfunc(a,b)
    14. `mataend'
    15.
    . end

    .
    .
    end of do-file

    . myprogram
    3+5
    8

    . myprogram
    3+5
    myprogram.myfunc() already exists
    r(3000);

    . myprogram
    3+5
    myprogram.myfunc() already exists
    r(3000);

    //////////////////////////////////////////////////////////////////

    How can I repeat using the program without running do-file?

    Thanks for reading.
    Last edited by Seongjin Jin; 03 Nov 2017, 12:26.

  • #2
    Seongjin Jin --

    I don't know if this helps, but the usual structure when you write an .ado file is to put all the code at the top, and any mata function that you call from within the code at the bottom. So, I might write up your program something like the following in an .ado file:

    Code:
    program myprogram
    version 13
    local a 3
    local b 5
    local mataend "end"
    di "`a'+`b'"
    mata: a=strtoreal(st_local("a"))
    mata: b=strtoreal(st_local("b"))
    mata: myfunc(a,b)
    end
    mata:
    void myfunc(c,d){
    c+d
    }
    end
    You should then have no problem is you save it as an .ado file and put it somewhere on the Stata path. But I'm not sure if that's what you want...

    Comment


    • #3
      Thanks a lot!
      The simplified program works okay now.

      Then can I ask one more?
      I guess that the previous problem above occurred because I put the mata function in the middle of stata program.

      However, I had mata function in the middle of stata program for a reason.
      The reason was to customize the number of arguments of mata function.
      If I put mata function at the bottom of my .do file, I could not customize the number of arguments.

      Here is the example of my situation:

      Code:
      capture gen a = 1
      capture gen b = 2
      capture gen c = 3
      program myprogram
      version 13
      // suppose myprogram take `data' and `func' as arguments
      // for example,
      // `data' could be "a,b"
      // `func' could be "a+2*b"
      local mataend "end"
      mata:
      void eval1(`data') {
      v=(`func')
      v
      }
      eval1(`data')
      `mataend'
      end

      Since I declare the mata function in the middle of stata program, if I put "a,b,c" and "a+2*b-c" as `data' and `func', the mata function would take three arguments.
      If I put the mata function, eval1, on the bottom of code and out of program, it would not take local macros such as `data' and `func'.

      So your suggestion totally works for the simplified program, but not work for my specific situation.
      Is there any solution that I can have the mata function which is able to contain changeable number of arguments?
      Last edited by Seongjin Jin; 03 Nov 2017, 14:12.

      Comment


      • #4
        Seongjin Jin A more direct approach is to use optional arguments (help m2_optargs).
        The problem with your approach is that you have to drop the mata function every time you call the program. You should add the following line before the definition of the function

        Code:
        cap mata: mata drop eval1()
        But generally, Mata functions should be defined outside the program. A better approach in my opinion is then to define your function with optional arguments , where the number of arguments to pass to the function is tested within your program in order to call the right syntax.

        Here is an example

        Code:
        program myprogram
        
        // count number of arguments in local nargs, the arguments are `arg1' and possibly `arg2'
        
        if (`nargs'==2) mata:eval1(`arg1', `arg2') // if `arg1' is a string then it should be within quotes
        else mata:eval1(`arg1')
        
        
        end
        
        
        mata:
        void eval1(arg1,|  arg2)
        {
        
        if (args()==2) {
        
        
        }
        else {
        
        
        }
        
        
        }
        
        end
        Last edited by Christophe Kolodziejczyk; 04 Nov 2017, 01:08.

        Comment


        • #5
          Thanks for the helpful comment, @Christophe Kolodziejczyk!
          I guess your suggestion makes the code customize the number of arguments for the mata function.
          However, I think it can only react with predetermined number of arguments, like 1 and 2 in the code example you wrote.

          What I originally want is the mata function which can have any number of arguments from user.
          For example, I don't know how many `nargs' are passed by users.
          It could be 4 or 6.
          However, the code above is designed for `nargs'=1 or 2.
          Even though I coded it up for `nargs' to 6, still I need the room for users to use `nargs' to 9 or 13.

          So that's why I tried to use global macro for the list of mata function arguments.
          Then I thought I can define the mata function outside of stata program and properly take user's customized the number of arguments.
          However, it didn't work well. I guess the reason was my misuse of global macro.
          It seems the program couldn't find global macro until it takes certain command for it.

          My simplified code using global macro looks like below:

          Code:
          capture program drop myprogram
          program myprogram
              version 13
              global argulist "price , mpg"
              global funcexp "2*price[1 , .] + mpg[1 , .], price[ 1 , . ] + 2*mpg[1,.]"
              // suppose I can get the contents of $argulist and $funcexp from user's command
              local argument "price mpg turn"    
              putmata `argument',replace
              mata: myfunc( $argulist )
          end
          
          cap mata: mata drop myfunc()
          mata:
          function myfunc( $argulist ) {    
              eval( $argulist )
          }
          end
          
          cap mata: mata drop eval()
          mata:
          void eval( $argulist ) {
                  result = ( $funcexp )
                  mean(result)        
          }
          end
          The code above is working with the commands below:
          Code:
          .sysuse auto
          .myprogram

          However, if I code the program which take global macro from user's command, I had a problem.
          It leads a problem when I ran the .do file of the program.
          In the process of defining stata program and mata functions, mata recognize I just gave no argument to mata function because we don't have a content of global macro yet.

          All I want to do is having mata function which can have flexible number of arguments by user's choice. How can I achieve that?

          P.S. What is my specific goal exactly? I want to calculate some statistics from user-given function and data. And that calculation contains the optimization process, so that's why I need the mata function in the mata code and the mata function needs to take arguments like function and data.
          Last edited by Seongjin Jin; 04 Nov 2017, 10:21.

          Comment


          • #6
            Well, that was just an example you can code your function with 13 optional arguments if you want.
            See this post for a more general and sophisticated approach to your problem, that is passing a function to another function where you don't know before hand the number of arguments. You might also take a look at the function mm_callf() from the moremata package (by Benn Jann).


            Comment


            • #7
              Thank you Christophe Kolodziejczyk !
              I had one short question though;;

              I can pass all my variable to mata by using putmata command.
              Then, is there other way to pass my variable to the mata function in the mata process than setting them as arguments?

              Actually, I tried to mimic gmm.ado, but it doesn't seem to pass it's variable to mata function.
              Last edited by Seongjin Jin; 04 Nov 2017, 12:08.

              Comment


              • #8
                Mata can see any arbitrary subset of Stata variables that you define in a local macro, and it can either reference them in a Mata view or create a Mata matrix from the local macro. That's the easy part.

                The hard part is defining an arbitrary function of them ad hoc in Mata. For that, you'd either have to have Mata call Stata back in order to use the latter's macro processing facility to define a (temporary) Mata function or write your own syntax parser in Mata.

                But you might be better off by taking a step back and looking at just what it is you're trying to do. There might be a better approach that can more straightforward to implement in Stata, Mata or their combination.

                Comment

                Working...
                X