*!  version 2.0.0 22Aug2005 - with ci's. renamed from prgen2 - for Stata 8
*  version 0.2.3 27May2005 - allow long strings
*  version 0.2.2 2005-02-03 jsl

//  generate predictions and ci's to plot

capture program drop prgen
program define prgen, rclass
    version 8
    tempname temp inc xval addbase tobase tobase2

//  check if prgen works with last model
    _pecmdcheck prgen
    local io = r(io)
    if "`io'"=="." {
        exit
    }
    local input : word 1 of `io'   /* input routine to _pepred */
    local output : word 2 of `io'  /* output routine */

//  decode options

    syntax [varlist(numeric min=1 max=1)] [if] [in] ///
        , Generate(string) [x(passthru) Rest(passthru) ///
        Level(passthru) MAXcnt(passthru) all ///
        Brief noBAse Ncases(integer 11) ///
        From(real -867.5309) To(real 867.5309) ///
        /// new options
        MARginal NOIsily CI gap(real 0.0) ///
        /// new options passed to prchange2 follow
        noLAbel noBAse Brief ///
        YStar ept DELta BOOTstrap REPs(passthru) SIze(passthru) ///
        DOts match NORMal PERCENTile BIAScorrected ///
        ]

    * marginals not available for these models
    if "`e(cmd)'"=="gologit" | "`input'"=="twoeq" ///
            | "`output'" == "tobit" ///
            | "`output'" == "regress" {
        if "`marginal'"=="marginal" {
            di _n in red "Note: Marginals not available for current model."
        }
        local marginal ""
    }

    * options to pass to prvalue
    local pr2input "`level' `maxcnt' `nolabel' `nobase' `brief'"
    local pr2input "`pr2input' `ystar' `ept' `delta' `bootstrap'"
    local pr2input "`pr2input' `reps' `size' `dots' `match'"
    local pr2input "`pr2input' `normal' `percentile' `biascorrected'"

    * print results from prvalue
    local quietly "quietly "
    if "`noisily'"=="noisily" {
        local quietly ""
        di "Results from prvalue called by prgen"
        di
    }

//  get information needed to create plot values

    local max_i = r(maxcount)
    _perhs
    local nrhs = `r(nrhs)'
    local rhsnms "`r(rhsnms)'"
    if "`input'"=="twoeq" {
        local nrhs2 = `r(nrhs2)'
        local rhsnms2 "`r(rhsnms2)'"
    }

    * get info from pecats if depvar not continuous
    if "`output'" != "regress" & "`output'" != "tobit" {
        _pecats
        local ncats = r(numcats)
        local catnms8 `r(catnms8)'
        local catvals `r(catvals)'
        local catnms `r(catnms)'
    }

    *get root() for generating new variables
    local root = substr("`generate'",1,29)
    if _rc != 0 {
        local root = substr("`generate'",1,5)
    }

    * convert input into base values
    _pebase `if' `in', `x' `rest' `choices' `all'
    mat `tobase' = r(pebase)
    if "`input'"=="twoeq" {
        mat `tobase2' = r(pebase2)
    }

    * create if to take e(sample) and if conditions into account
    _peife `if', `all'
    local if "`r(if)'"

    * set from and to to min and max of chngvar if unspecified
    qui sum `varlist' `if'
    if `from' == -867.5309 {
        local from = r(min)
    }
    if `to' == 867.5309 {
        local to = r(max)
    }

//  set up and test range to be plotted

    * check from and to
    if `from'>=`to' {
        di in r "from() must be < to()"
        exit
     }

    * turn gap into increments
    if `gap' != 0 {
        if `gap'<=0 {
            di in r "gap must be a positive value."
        }
        tempname range ngaps
        sca `range' = `to' - `from'
        sca `ngaps' = `range'/`gap'
        if  int(`ngaps')==`ngaps' {
            local ncases = `ngaps' + 1
        }
        else {
            di in r "gap does not divide evenly into from to interval."
        exit 198
        }
    }

    * verify valid number of plot points
    if `ncases' < 3 {
        di in r "ncases() must be greater than 3"
        exit 198
    }
    if `ncases' > _N {
        set obs `ncases'
    }
    sca `inc' = (`to'-`from')/(`ncases'-1)

//  find variables among those in model

    * locate specified variable among rhs variables
    local found "no"
    local varnum -1

    *look in main equation, if not there: varnum == -1
    local i2 = 1
    local i2_to : word count `rhsnms'
    while `i2' <= `i2_to' {
        local varchk : word `i2' of `rhsnms'
        unab varchk : `varchk', max(1)
        if "`varlist'"=="`varchk'" {
            local found "yes"
            local varnum = `i2'
            local i2 = `i2_to'
        }
        local i2 = `i2' + 1
    }

    * if zip,zinb look in inflate equation, if not there: varnum2 == -1
    if "`input'"=="twoeq" {
        local i3 = 1
        local i3_to : word count `rhsnms2'
        local varnum2 -1
        while `i3' <= `i3_to' {
            local varchk : word `i3' of `rhsnms2'
            unab varchk : `varchk', max(1)
            if "`varlist'"=="`varchk'" {
                local found "yes"
                local varnum2 = `i3'
                local i3 = `i3_to'
            }
            local i3 = `i3' + 1
        }
    }

    if "`found'"=="no" {
        di in r "`var' not rhs variable"
        exit 198
    }

//  insert from value into base values for initial call of prvalue

    mat PE_in = `tobase'
    * from to variable begins at from
    if `varnum' != -1 {
        mat PE_in[1, `varnum']=`from'
    }
    * for zip and zinb
    if "`input'"=="twoeq" {
        mat PE_in2 = `tobase2'
        if `varnum2' != -1 {
            mat PE_in2[1, `varnum2']=`from'
            }
    }

//  make x() string and compute predictions

* drop _pexstring // error with long string.
*      local xis = r(xis)
* 27May2005
    local xs_cols = colsof(PE_in)
    local xs_xnames : colnames PE_in
    local xs_xis ""
    foreach c of numlist  1/`xs_cols'  {
        local xs_xnm : word `c' of `xs_xnames'
        local xs_xval = PE_in[1,`c']
        local xs_xis "`xs_xis' `xs_xnm'=`xs_xval'"
    }
    `quietly' prvalue , x(`xs_xis') `pr2input'

//  get marginal

    if "`marginal'"=="marginal" {
        tempname  marg tempmarg
        _pemarg
        mat `tempmarg' = r(marginal)
        if "`output'"=="nominal" | "`output'"=="ordered" {
            mat `tempmarg' = `tempmarg''
        }
        mat `marg' = `tempmarg'[1...,`varnum']'
    }

//  create matrices to be converted to variables

    tempname x_pred  pr_pred  mu_pred  all0_pred  xb_pred catvals nextbase
    tempname pr_upper mu_upper all0_upper xb_upper
    tempname pr_lower mu_lower all0_lower xb_lower

    mat def `catvals' = pepred[1,1...]
    mat def `x_pred' = `from'

    local predset "pred"
    if "`ci'" == "ci" {
        local predset "`predset' upper lower"
    }
    foreach nm in `predset' {
        mat def `pr_`nm'' = pe`nm'[2,1...]
        mat def `mu_`nm'' = pe`nm'[3,2]
        mat def `xb_`nm'' = pe`nm'[3,1]
        mat def `all0_`nm'' = pe`nm'[3,4]
    }

//  loop from from value to to value

    local i = 2
    local i_to = `ncases'
    while `i' <= `i_to' {

        sca `xval' = `from' + (`inc'*(`i'-1))

        * change from variable value
        mat `nextbase' = `tobase'
        if `varnum' != -1 {
            mat `nextbase'[1, `varnum']=`xval'
        }
        mat PE_in = `nextbase'

        * create x() string
* drop _pexstring // error with long string.
*      local xis = r(xis)
* 27May2005
        local xs_cols = colsof(PE_in)
        local xs_xnames : colnames PE_in
        local xs_xis ""
        foreach c of numlist  1/`xs_cols'  {
            local xs_xnm : word `c' of `xs_xnames'
            local xs_xval = PE_in[1,`c']
            local xs_xis "`xs_xis' `xs_xnm'=`xs_xval'"
        }
        `quietly' prvalue , x(`xs_xis') `pr2input'

        * get marginal effect
        if "`marginal'"=="marginal" {
            _pemarg
            mat `tempmarg' = r(marginal)
            * some marginal matrices need to be transposed first
            if "`output'"=="nominal" | "`output'"=="ordered" {
                mat `tempmarg' = `tempmarg''
            }
            mat def `marg' = `marg' \ `tempmarg'[1...,`varnum']'
        }

        * stack new values in matrices
        mat def `x_pred' = `x_pred' \ `xval'
        foreach nm in `predset' {
            mat def `pr_`nm'' = `pr_`nm'' \ pe`nm'[2,1...]
            mat def `mu_`nm'' = `mu_`nm'' \ pe`nm'[3,2]
            mat def `xb_`nm'' =`xb_`nm'' \ pe`nm'[3,1]
            if "`input'"=="twoeq" {
                mat def `all0_`nm'' =`all0_`nm'' \ pe`nm'[3,4]
            }
        }

        local i = `i' + 1
    }

//  create plot variables

    * x variable
    svmat `x_pred', n(`root'x)
    rename `root'x1 `root'x
    label variable `root'x "Changing value of `varlist'"

    * marginal effects
    if "`marginal'"=="marginal" {
        local margnm : word `varnum' of `rhsnms'
        svmat `marg', n(`root'me_`margnm')
    }

//  binary, ordered, nominal or count

    if "`output'"=="binary" | "`output'"=="nominal"  ///
        | "`output'"=="ordered" ///
        | "`output'"=="count" {

        * predictions and bounds
        svmat `pr_pred', n(temp)
        if "`ci'"=="ci" {
            svmat `pr_lower', n(templb)
            svmat `pr_upper', n(tempub)
        }

        * process each outcome probability
        local ncats = peinfo[1,2]
        foreach i of numlist  1/`ncats'  {

            * get # assigned to first category
            local value = `catvals'[1,`i']
            local k`i' = `value'

            * if value are too large or small
            if `value' < -9 | `value' > 99 | int(`value')!=`value' {
                di in red "category values must be integers between -9 and 99"
                exit 198
            }

            * if negative create name using _
            if `value' < 0 {
                local k`i' = abs(`k`i'')
                local k`i' = "_`k`i''"
            }

            * rename and label probability
            rename temp`i' `root'p`k`i''
            local lbl: word `i' of `catnms8'

            * get information to label variables
            if "`lbl'"=="`value'" {
                local fvalue "" // same, so only use 1
            }
            else {
                local fvalue "=Pr(`value')"
            }
            if "`lbl'"=="" {
                local lbl "`value'"
                local fvalue ""
            }
            if "`nolabel'"!="nolabel" {
                label variable `root'p`k`i'' "pr(`lbl')`fvalue'"
            }
            else {
                label variable `root'p`k`i'' "pr(`value')"
            }

            * process upper and lower bounds
            if "`ci'"=="ci" {
                rename tempub`i' `root'p`k`i''ub
                if "label'"!="nolabel" {
                    label variable `root'p`k`i''ub "UB pr(`lbl')`fvalue'"
                }
                else {
                    label variable `root'p`k`i'' "UB pr(`value')"
                }
                rename templb`i' `root'p`k`i''lb
                if "label'"!="nolabel" {
                    label variable `root'p`k`i''lb "LB pr(`lbl')`fvalue'"
                }
                else {
                    label variable `root'p`k`i'' "LB pr(`value')"
                }
            }

            * create variables summing prob of being <= k
            if `ncats'>2 {
                if `i' == 1 {
                    qui gen `root's`k1' = `root'p`k1'
                }
                else {
                    local i_min1 = `i' - 1
                    qui gen `root's`k`i'' = `root'p`k`i'' + `root's`k`i_min1''
                }
                label variable `root's`k`i'' "pr(y<=`value')"
            }

            * marginals
            if "`marginal'"=="marginal" & ///
                    "`output'"!="count" {  // no marg pr# for count
                rename `root'me_`margnm'`i' `root'Dp`k`i''D`margnm'
                label variable `root'Dp`k`i''D`margnm' ///
                    "Marginal dp`k'`i'/d`margnm'"
            }

        } // end of loop through categories

    } // binary, ordered, nominal or count

//  REGRESS/TOBIT MODELS

    if "`output'"=="regress" | "`output'"=="tobit" {

        svmat `xb_pred', n(`root'xb)
        rename `root'xb1 `root'xb

        if "`ci'" == "ci" {
            svmat `xb_lower', n(`root'xblb)
            rename `root'xblb1 `root'xblb
            svmat `xb_upper', n(`root'xbub)
            rename `root'xbub1 `root'xbub
        }

        if "`output'"=="regress" {
            label variable `root'xb "y-hat"
            if "`ci'" == "ci" {
                label variable `root'xblb "UB y-hat"
                label variable `root'xbub "LB y-hat"
            }
        }

        if "`output'"=="tobit" {
            label variable `root'xb "y*-hat"
            if "`ci'" == "ci" {
                label variable `root'xblb "UB y*-hat"
                label variable `root'xbub "LB y*-hat"
            }
        }
    } // regress/tobit

//  for count models, process mu and prall0

    if "`output'"=="count" {

        * marginals
        if "`marginal'"=="marginal" {
            mat list `marg'
            drop `root'me_`margnm'1
            rename `root'me_`margnm'2 `root'DmuD`margnm'
            label var `root'DmuD`margnm' "Marginal dmu/d`margnm'"
        }

        * mu
        svmat `mu_pred', n(`root'mu)
        rename `root'mu1 `root'mu
        label variable `root'mu "predicted rate mu"

        * upper and lower bounds
        if "`ci'"=="ci" {
            svmat `mu_lower', n(`root'mulb)
            rename `root'mulb1 `root'mulb
            label variable `root'mulb "LB predicted rate mu"
            svmat `mu_upper', n(`root'muub)
            rename `root'muub1 `root'muub
            label variable `root'muub "UB predicted rate mu"
        }

        if "`input'"=="twoeq" {
            svmat `all0_pred', n(`root'all0)
            rename `root'all01 `root'all0
            label variable `root'all0 "pr(Always-0)"
            if "`ci'"=="ci" {
                svmat `all0_lower', n(`root'all0lb)
                rename `root'all0lb1 `root'all0lb
                label variable `root'all0lb "LB pr(Always-0)"
                svmat `all0_upper', n(`root'all0ub)
                rename `root'all0ub1 `root'all0ub
                label variable `root'all0ub "UB pr(Always-0)"
            }
        }

    } // mu and prob always 0

//  COMMON OUTPUT

    if "`brief'"=="" & "`base'"!="nobase" {
        di _n in y "`e(cmd)'" in g ": Predicted values as " /*
        */ in y "`varlist'" in g /*
        */ " varies from " in y "`from'" in g " to " /*
        */ in y "`to'" in g "."

        *print base values
        if "`input'"=="twoeq" {
            di _n in g "base x values for count equation: "
        }
        mat rownames `tobase' = "x="
        mat _PEtemp = `tobase'
        _peabbv _PEtemp
        mat list _PEtemp, noheader
        if "`input'"=="twoeq" {
            di _n in g "base z values for binary equation: "
            mat rownames `tobase2' = "z="
            mat _PEtemp = `tobase2'
            _peabbv _PEtemp
            mat list _PEtemp, noheader
        }
    }

end