-
Notifications
You must be signed in to change notification settings - Fork 1
/
cmp.ado
2828 lines (2579 loc) · 130 KB
/
cmp.ado
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
*! cmp 8.7.9 18 April 2024
*! Copyright (C) 2007-24 David Roodman
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Version history at bottom
cap program drop cmp
program define cmp, sortpreserve properties(user_score svyb svyj svyr mi fvaddcons) byable(recall)
version 11
cap version 13.0
if _rc {
di as err "This version of {cmd:cmp} requires Stata version 13 or later. An older version compatible with Stata `c(stata_version)'"
di as err "is at https://github.com/droodman/cmp/releases/tag/v8.6.1."
exit _rc
}
cap noi _cmp `0'
if _rc {
local rc = _rc
if _rc>1 cmp_clear
error `rc'
}
end
cap program drop _cmp
program define _cmp
version 11
if replay() {
if "`e(cmd)'" != "cmp" error 301
if _by() error 190
Display `0'
exit 0
}
cmp_clear
global cmp_out 0
global cmp_cont 1
global cmp_left 2
global cmp_right 3
global cmp_probit 4
global cmp_oprobit 5
global cmp_mprobit 6
global cmp_int 7
global cmp_trunc 8 // deprecated
global cmp_probity1 8 // now used in cmp_ind* vars to indicate probit obs with y!=0
global cmp_roprobit 9
global cmp_frac 10
global cmp_missing .
if `"`0'"' == "setup" {
di as txt "$" "cmp_out = " as res 0
di as txt "$" "cmp_missing = " as res .
di as txt "$" "cmp_cont = " as res 1
di as txt "$" "cmp_left = " as res 2
di as txt "$" "cmp_right = " as res 3
di as txt "$" "cmp_probit = " as res 4
di as txt "$" "cmp_oprobit = " as res 5
di as txt "$" "cmp_mprobit = " as res 6
di as txt "$" "cmp_int = " as res 7
di as txt "$" "cmp_trunc = " as res 8 as txt " (deprecated)"
di as txt "$" "cmp_roprobit = " as res 9
di as txt "$" "cmp_frac = " as res 10
exit 0
}
cap ghk2version
if _rc | "`r(version)'" < "01.70.00" {
di as err "Error: {cmd:cmp} works with {cmd:ghk2()} version 1.7.0 or later."
di `"To install or update it, type or click on {stata "ssc install ghk2, replace"}. Then restart Stata."'
exit 601
}
syntax anything(equalok id="model" name=model) [pw fw aw iw] [if] [in], INDicators(string asis) [svy GHKAnti GHKDraws(string) ///
GHKType(string) QUIetly noLRtest CLuster(varname) Robust vce(string) Level(real `c(level)') RESULTsform(string) predict(string) ///
CONSTraints(passthru) TECHnique(string) INTERactive noDRop init(namelist min=1 max=1) from(namelist min=1 max=1) lf pseudod2 PSampling(numlist min=1 max=2) ///
STRUCtural REVerse noESTimate REDraws(string) COVariance(string) INTPoints(string) INTMethod(string) noAUTOconstrain noSIGXform *]
if "`pseudod2'" != "" cmp_error 198 "The pseudod2 option is no longer supported."
if "`from'" != "" {
if "`init'" != "" cmp_error 198 "Cannot specify both {cmd:init()} and {cmd:from()}."
local init `from'
}
local cmdline `0'
mata _mod = cmp_model()
global parse_wtypeL `weight'
tokenize `"`exp'"'
macro shift // get rid of = prefix
global parse_wexpL `*'
local structural = "`structural'" != ""
global cmp_reverse = "`reverse'" != ""
mata _mod.setReverse($cmp_reverse)
global cmpSigXform = "`sigxform'" ==""
mata _mod.setSigXform($cmpSigXform)
if $cmpSigXform {
local ln ln
local atanh atanh
}
marksample touse, strok
_get_eformopts, soptions eformopts(`options') allowed(hr shr IRr or RRr)
local eformopts `s(eform)'
_get_mldiopts, `s(options)'
local mldiopts `s(diopts)'
if "`svy'" != "" {
if "`_dta[_svy_stages]'"=="" {
di as res _n "Warning: data not svyset. Ignoring " as inp "svy" as res "."
local svy
}
else {
svymarkout `touse'
svyopts modopts svydiopts options, `s(options)'
local meff `s(meff)'
local 0, `modopts'
local _options `options'
syntax, [subpop(string) *]
local modopts `options'
local options `_options'
if `"`subpop'"' != "" {
cap confirm var `subpop'
if _rc {
tempvar subpop
qui gen byte `subpop' = `s(subpop)' & `touse'
}
}
}
}
else local options `s(options)'
local diopts `eformopts' `mldiopts' `svydiopts' level(`level') resultsform(`resultsform')
mlopts mlopts, `options'
local 0, `mlopts'
syntax, [iterate(passthru) *]
local mlopts `options'
ParseEqs `model' // parse the equations
global cmp_d $parse_d
if $parse_L == 1 global cmp_IntMethod 0
else {
if `"`redraws'"'=="" {
if "`intmethod'"'!="" {
local 0 `intmethod'
local _iterate `iterate'
syntax [anything(name=intmethod)], [TOLerance(real 1e-8) ITERate(integer 1001)]
if `tolerance'<=0 cmp_error 198 "Adaptive quadrature tolerance must be positive."
if `iterate'<=0 cmp_error 198 "Maximum adaptive quadrature iterations must be positive."
mata _mod.setQuadTol(`tolerance'); _mod.setQuadIter(`iterate')
local iterate `_iterate'
}
else mata _mod.setQuadTol(1e-3); _mod.setQuadIter(1001)
if "`intmethod'"'=="" local intmethod mvaghermite
local 0, `intmethod'
syntax, [Ghermite MVAghermite]
local methods ghermite mvaghermite
local t: list posof "`ghermite'`mvaghermite'" in methods
if `t' global cmp_IntMethod = `t' - 1
else cmp_error 198 `"The {cmdab:intm:ethod()} option, if included, should be "ghermite" or "mvaghermite"."'
if `"`vce'`svy'`robust'`cluster'"'=="" local vce oim
if "`technique'"=="" & !("`svy'"!="" & date(c(born_date),"DMY")<d(30jan2018)) { // moptimize() would crash with BHHH & svy & gfX evaluators
local technique bhhh
di as res _n "For quadrature, defaulting to technique(bhhh) for speed."
}
}
else global cmp_IntMethod 0
}
local 0 `ghkdraws'
syntax [anything], [type(string) ANTIthetics SCRamble *]
if `"`options'"' != "" {
local 0, `options'
syntax, [SCRamble(string)]
}
else if "`scramble'" != "" local scramble sqrt
if `"`scramble'"' != "" {
local 0, `scramble'
syntax, [sqrt NEGsqrt fl]
local scramble `sqrt'`negsqrt'`fl'
}
if `"`ghktype'"' != "" & `"`type'"' != "" & `"`ghktype'"' != `"`type'"' & `"`ghktype'`type'"' != "halton" {
di as res _n "Warning: {cmd:type(`type')} suboption overriding deprecated {cmd:ghktype(`ghktype')} option."
}
if `"`type'"' != "" local ghktype `type'
local 0, ghkdraws(`anything')
syntax, [ghkdraws(numlist integer>=`=c(stata_version)<15' max=1)] // In Stata 15+, allow ghkdraws(0) to trigger use of mvnormal()
if "`ghkdraws'" == "" | 0`ghkdraws' {
if `"`ghktype'"'=="" local ghktype halton
else if inlist(`"`ghktype'"', "halton", "hammersley", "ghalton", "random") == 0 {
cmp_error 198 `"The {cmdab:ghkt:ype()} option must be "halton", "hammersley", "ghalton", or "random". It corresponds to the {cmd:{it:type}} option of {cmd:ghk()}. See help {help mf_ghk}."'
}
if "`scramble'"!="" & "`type'"=="ghalton" {
di as res "Warning: {cmd:scramble} in {cmd:ghkdraws()} option incompatible with {cmd:ghalton}. {cmd:scramble} ignored."
local scramble
}
if 0`ghkdraws' mata _mod.CheckPrime(`ghkdraws')
local ghkanti = "`antithetics'`ghkanti'"!=""
mata _mod.setGHKType("`ghktype'"); _mod.setGHKAnti(`ghkanti'); _mod.setGHKDraws(0`ghkdraws'); _mod.setGHKScramble("`scramble'")
local ghkscramble `scramble'
}
if `"`covariance'"' == "" {
forvalues l=1/$parse_L {
global cmp_cov`l' unstructured
}
}
else {
local covariance: subinstr local covariance "." "unstructured", word all
if `:word count `covariance'' != $parse_L cmp_error 198 "The {cmdab:cov:ariance()}, if used, must contain one entry for each of the $parse_L levels in the model."
else {
tokenize `covariance'
forvalues l=1/$parse_L {
local 0, ``l''
syntax, [UNstructured EXchangeable INDependent]
global cmp_cov`l' `unstructured'`exchangeable'`independent'
if inlist("${cmp_cov`l'}", "unstructured", "exchangeable", "independent") == 0 {
cmp_error 198 `"Each entry in the {cmdab:cov:ariance()} option must be "unstructured", "." (equivalent to "unstructured"), "exchangeable", or "independent"."'
}
}
}
}
forvalues l=1/$parse_L {
local FixedRhoFill`l' = cond("${cmp_cov`l'}"=="independent", 0, .)
}
local t: subinstr local indicators "(" "", all
if $cmp_d != `:word count `:subinstr local t ")" "", all'' cmp_error 198 `"The {cmdab:ind:icators()} option must contain $cmp_d `=plural($cmp_d,"variable","variables, one for each equation")'. Did you forget to type {stata "cmp setup"}?"'
mata _mod.setQuadrature(0); _mod.setREAnti(1)
if $parse_L > 1 {
if `"`redraws'"' == "" {
if `"`intpoints'"' == "" {
forvalues l=2/$parse_L {
local intpoints `intpoints' 12 // default precision level for quadrature
}
local redraws `intpoints'
}
else {
local 0, intpoints(`intpoints')
syntax, [intpoints(numlist integer>=1)]
if $parse_L!=`:word count `intpoints''+1 cmp_error 198 "If included, the intpoints() should have one entry for each level except the lowest."
tokenize `intpoints'
forvalues l=1/`=$parse_L-1' {
if ``l'' > 25 {
di as res "Warning: quadrature precision limited to the equivalent of 25 integration points."
local `l' 25
}
local redraws `*'
}
}
local steps 1
mata _mod.setQuadrature(1); _mod.setREAnti(1)
}
else {
if `"`intpoints'"' != "" cmp_error 198 "intpoints() and redraws() options conflict. Use one or neither. (Default: sparse-grid quadrature with precision equivalent to 12 integration points.)"
local 0 `redraws'
syntax [anything], [type(string) ANTIthetics STeps(numlist integer min=1 max=1 >0) SCRamble *]
if `"`options'"' != "" {
local 0, `options'
syntax, [SCRamble(string)]
}
else if "`scramble'" != "" local scramble sqrt
if `"`scramble'"' != "" {
local 0, `scramble'
syntax, [sqrt NEGsqrt fl]
local scramble `sqrt'`negsqrt'`fl'
}
local 0, redraws(`anything')
syntax, [redraws(numlist integer>=1)]
if $parse_L!=`:word count `redraws''+1 cmp_error 198 "If included, the redraws() option should have one entry for each level except the lowest."
if `"`type'"'=="" local type halton
else if inlist(`"`type'"', "halton", "hammersley", "ghalton", "random") == 0 {
cmp_error 198 `"The {cmd:redraws()} {cmd:type()} suboption must be "halton", "hammersley", "ghalton", or "random"."'
}
if "`type'"=="hammersley" & "`ghktype'"=="hammersley" {
cmp_error 198 "Random effects and GHK sequences shouldn't both be Hammersley since this will assign the same draws to the first dimension of each."
}
if "`scramble'"!="" & "`type'"=="ghalton" {
di as res "Warning: {cmd:scramble} in {cmd:redraws()} option incompatible with {cmd:ghalton}. {cmd:scramble} ignored."
local scramble
}
mata _mod.CheckPrime(strtoreal(tokens("`redraws'")))
mata _mod.setREType("`type'"); _mod.setREAnti(1+("`antithetics'"!= "")); _mod.setREScramble("`scramble'")
}
}
if 0`steps'==0 local steps 1
global cmp_max_cuts 0
global cmp_num_mprobit_groups 0
global cmp_num_roprobit_groups 0
global cmp_mprobit_ind_base 20
global cmp_roprobit_ind_base 40
global cmp_intreg 0
global cmp_truncreg 0
local asprobit_eq 0
tempvar _touse n asmprobit_dummy_sum asmprobit_ind
qui {
gen byte `_touse' = 0
tokenize `"`indicators'"', parse("() ")
local parse_eqno 0
local cmp_eqno 0
while `"`1'"' != "" {
if (`"`1'"' == ")" & `asprobit_eq' == 0) | (`"`1'"' == "(" & `asprobit_eq') cmp_error 132 "Too many `1'"
if `"`1'"'==")" {
if "`m_ro'" == "m" {
cap assert `asmprobit_dummy_sum'==1 if `touse' & _cmp_ind`first_asprobit_eq', fast
if _rc cmp_error 132 "For multinomial probit groups, exactly one dependent variable must be non-zero for each observation."
replace _cmp_ind`first_asprobit_eq'=`asmprobit_ind'*(_cmp_ind`first_asprobit_eq'!=0) // store choice info in indicator var for first equation
drop `asmprobit_ind' `asmprobit_dummy_sum'
}
mat cmp_`m_ro'probit_group_inds[${cmp_num_`m_ro'probit_groups}, 2] = `cmp_eqno'
mat cmp_nonbase_cases = nullmat(cmp_nonbase_cases) , 0 , J(1, `asprobit_eq'-2, 1)
local asprobit_eq 0
local m_ro
macro shift
continue
}
local ++parse_eqno
local ++cmp_eqno
local NAlts 0
if `"`1'"'=="(" {
macro shift
if `"`1'"' == ")" continue
local asprobit_eq 1
local first_asprobit_eq `cmp_eqno'
if "${parse_x`parse_eqno'}" != "" global parse_xc`parse_eqno' nocons // put nocons for first eq in asprobit group or (below, after eq gets its name) leave cons in but constrained to 0
}
cap gen byte _cmp_ind`cmp_eqno' = `1'
if _rc cmp_error 198 `"Error building indicator variable for equation `cmp_eqno' from expression `1'. Did you forget to type {stata "cmp setup"}?"'
if "${parse_y`parse_eqno'}"=="." {
cap assert inlist(_cmp_ind`cmp_eqno', ., 0) if `touse', fast
if _rc cmp_error 198 `"Indicator for ${parse_eq`parse_eqno'} equation must only evaluate to missing (".") or 0 since the dependent variable is unobserved."'
}
else {
cap assert inlist(_cmp_ind`cmp_eqno', ., 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) if `touse', fast
if _rc cmp_error 198 "Indicator for ${parse_y`parse_eqno'} must only evaluate to integers between 0 and 10."
replace _cmp_ind`cmp_eqno' = $cmp_cont if _cmp_ind`cmp_eqno'==$cmp_trunc // deprecate this indicator value
}
foreach macro in eq x xc xo xe y yR id {
global cmp_`macro'`cmp_eqno' ${parse_`macro'`parse_eqno'}
}
markout _cmp_ind`cmp_eqno' ${cmp_xo`cmp_eqno'} ${cmp_xe`cmp_eqno'} `:subinstr global cmp_id`cmp_eqno' "_n" "", all word'
if "${cmp_xe`cmp_eqno'}" != "" replace _cmp_ind`cmp_eqno' = 0 if ${cmp_xe`cmp_eqno'}<=0
cap assert _cmp_ind`cmp_eqno' != $cmp_int if `touse', fast
if _rc {
if `:word count ${cmp_y`cmp_eqno'}' != 2 cmp_error 198 "Interval regression equations require two dependent variables."
global cmp_y`cmp_eqno'_L : word 1 of ${cmp_y`cmp_eqno'}
gen double _cmp_y`cmp_eqno' = `: word 2 of ${cmp_y`cmp_eqno'}' if `touse' // copy so can modify below in converting some obs to Tobits for efficiency
global cmp_y`cmp_eqno' _cmp_y`cmp_eqno'
global cmp_intreg 1
global cmp_intreg`cmp_eqno' 1
mat cmp_intregeqs = nullmat(cmp_intregeqs), 1
replace _cmp_ind`cmp_eqno' = ${cmp_y`cmp_eqno'}<. if _cmp_ind`cmp_eqno'==$cmp_int & ${cmp_y`cmp_eqno'}==${cmp_y`cmp_eqno'_L}
replace _cmp_ind`cmp_eqno' = 0 if _cmp_ind`cmp_eqno'==$cmp_int & ${cmp_y`cmp_eqno'} < ${cmp_y`cmp_eqno'_L} & ${cmp_y`cmp_eqno'_L} < .
markout _cmp_ind`cmp_eqno' ${parse_x`parse_eqno'}
}
else {
mat cmp_intregeqs = nullmat(cmp_intregeqs), 0
markout _cmp_ind`cmp_eqno' ${parse_x`parse_eqno'} // `=cond("${parse_y`parse_eqno'}"!="." & , "${parse_y`parse_eqno'}", "")'
global cmp_intreg`cmp_eqno' 0
global cmp_y`cmp_eqno'_L . // to prevent syntax errors
}
if `"${parse_tr`parse_eqno'}"' != "" { // truncated regression
gen double _cmp_Lt`cmp_eqno' = `:word 1 of ${parse_tr`parse_eqno'}'
gen double _cmp_Ut`cmp_eqno' = `:word 2 of ${parse_tr`parse_eqno'}'
mat cmp_trunceqs = nullmat(cmp_trunceqs), 1
global cmp_Lt`cmp_eqno' _cmp_Lt`cmp_eqno'
global cmp_Ut`cmp_eqno' _cmp_Ut`cmp_eqno'
global cmp_truncreg 1
global cmp_truncreg`cmp_eqno' 1
count if _cmp_ind`cmp_eqno' & `touse'
local N = r(N)
replace _cmp_ind`cmp_eqno' = 0 if `touse' & inlist(_cmp_ind`cmp_eqno', $cmp_cont, $cmp_left, $cmp_right) & ///
((${cmp_y`cmp_eqno'}<=${cmp_Lt`cmp_eqno'} & ${cmp_Lt`cmp_eqno'}<.) | ${cmp_y`cmp_eqno'}>=${cmp_Ut`cmp_eqno'})
replace _cmp_ind`cmp_eqno' = 0 if `touse' & _cmp_ind`cmp_eqno'==$cmp_trunc & ///
((${cmp_y`cmp_eqno'}<=${cmp_Lt`cmp_eqno'} & ${cmp_Lt`cmp_eqno'}<.) | ${cmp_y`cmp_eqno'_L}>=${cmp_Ut`cmp_eqno'})
replace _cmp_ind`cmp_eqno' = 0 if `touse' & _cmp_ind`cmp_eqno'==$cmp_probit & ///
((0<${cmp_Lt`cmp_eqno'} & ${cmp_Lt`cmp_eqno'}<.) | 0>${cmp_Ut`cmp_eqno'}) // truncation range must embrace 0 for probits
count if _cmp_ind`cmp_eqno' & `touse'
if r(N)!=`N' di as res `N'-r(N) " observations dropped because dependent variable in equation `parse_eqno' is outside truncation range."
if ${cmp_intreg`cmp_eqno'} {
gen double _cmp_y`cmp_eqno'_L = ${cmp_y`cmp_eqno'_L}
global cmp_y`cmp_eqno'_L _cmp_y`cmp_eqno'_L
global cmp_y`cmp_eqno' _cmp_y`cmp_eqno'
replace _cmp_y`cmp_eqno'_L = _cmp_Lt`cmp_eqno' if `touse' & _cmp_ind`cmp_eqno'==$cmp_int & (_cmp_y`cmp_eqno'_L==. | (_cmp_y`cmp_eqno'_L<_cmp_Lt`cmp_eqno' & _cmp_Lt`cmp_eqno'<.))
replace _cmp_y`cmp_eqno' = _cmp_Ut`cmp_eqno' if `touse' & _cmp_ind`cmp_eqno'==$cmp_int & _cmp_y`cmp_eqno' >_cmp_Ut`cmp_eqno'
}
}
else {
global cmp_truncreg`cmp_eqno' 0
mat cmp_trunceqs = nullmat(cmp_trunceqs), 0
global cmp_Lt`cmp_eqno' .
global cmp_Ut`cmp_eqno' .
}
global cmp_eq`cmp_eqno' = cond("${parse_eq`parse_eqno'}"=="eq`parse_eqno'", subinstr("`: word 1 of ${parse_y`parse_eqno'}'", ".", "", .), "${parse_eq`parse_eqno'}")
if "`:list eqnames & global(cmp_eq`cmp_eqno')'" != "" global cmp_eq`cmp_eqno' `=substr("${cmp_eq`cmp_eqno'}",1,29)'`cmp_eqno'
local eqnames `eqnames' ${cmp_eq`cmp_eqno'}
if 0`first_asprobit_eq' == `cmp_eqno' & "${parse_x`parse_eqno'}" == "" { // if this is an mprobit base case with no regressors, leave cons in but constrain to 0
constraint free
local _constraints `_constraints' `r(free)'
constraint `r(free)' [${cmp_eq`parse_eqno'}]_cons
}
replace `_touse' = `_touse' | _cmp_ind`cmp_eqno'
cap assert _cmp_ind`cmp_eqno' != $cmp_oprobit if `touse', fast
mat cmp_num_cuts = nullmat(cmp_num_cuts) \ _rc // _rc is a placeholder non-zero value, to be corrected later
if _rc { // ordered probit
local i_oprobit_ys `i_oprobit_ys' i._cmp_y`cmp_eqno'
global cmpAnyOprobit 1
}
else local lrtest `lrtest' ${cmp_xc`cmp_eqno'}
cap assert _cmp_ind`cmp_eqno' != $cmp_frac if `touse', fast
if _rc {
local hasfrac 1
cap assert (${cmp_y`cmp_eqno'} >= 0 & ${cmp_y`cmp_eqno'} <= 1) | ${cmp_y`cmp_eqno'} >= . if `touse' & _cmp_ind`cmp_eqno'==$cmp_frac, fast
if _rc cmp_error 198 "Observations of dependent variable for fractional probit equation must be in [0,1]."
}
count if _cmp_ind`cmp_eqno'==$cmp_mprobit & `touse'
local N_mprobit `r(N)'
count if _cmp_ind`cmp_eqno'==$cmp_roprobit & `touse'
local N_roprobit `r(N)'
if `N_mprobit' | `N_roprobit' { // multinomial or rank-ordered probit
if (`N_mprobit' & "`m_ro'" == "ro") | (`N_roprobit' & "`m_ro'" == "m") cmp_error 148 "Cannot mix multinomial and rank-ordered indicator values in the same group."
cap assert inlist(_cmp_ind`cmp_eqno', 0, $cmp_mprobit, $cmp_roprobit) if `touse', fast
if _rc | `N_mprobit'&`N_roprobit' cmp_error 198 `"Dependent variables modeled as `=cond(`N_mprobit',"multinomial","rank-ordered")' probit may not be modeled differently for other observations in the same equation."'
if ${cmp_truncreg`cmp_eqno'} cmp_error 198 `'"Truncation not allowed in `=cond(`N_mprobit',"multinomial","rank-ordered")' probit equations."'
if `asprobit_eq'==1 & "`m_ro'" == "" { // starting new asprobit group?
if `N_mprobit' {
gen byte `asmprobit_dummy_sum' = 0 if `touse'
gen byte `asmprobit_ind' = $cmp_mprobit_ind_base + `cmp_eqno' - 1 if `touse'
local m_ro m
}
else local m_ro ro
global cmp_num_`m_ro'probit_groups = ${cmp_num_`m_ro'probit_groups} + 1
mat cmp_`m_ro'probit_group_inds = nullmat(cmp_`m_ro'probit_gr oup_inds) \ (`cmp_eqno', .)
}
if `asprobit_eq' == 0 { // non-as mprobit?
if `N_roprobit' cmp_error 148 "Rank-ordered probit indicators must be grouped in parentheses."
global cmp_num_mprobit_groups = $cmp_num_mprobit_groups + 1
GroupCategoricalVar if `touse' & _cmp_ind`cmp_eqno'==$cmp_mprobit, predict(`predict') cmp_eqno(`cmp_eqno')
mat cmp_cat`cmp_eqno' = r(cat)
local NAlts = colsof(cmp_cat`cmp_eqno') - 1
if `NAlts' == 0 cmp_error 148 "There is only one outcome in ${cmp_y`cmp_eqno'}."
if $cmp_max_cuts < `NAlts' global cmp_max_cuts = `NAlts' // hack for including cmp_y`cmp_eqno'_label in e(cat) for use after predict just below
mat cmp_mprobit_group_inds = nullmat(cmp_mprobit_group_inds) \ (`cmp_eqno', `cmp_eqno'+`NAlts')
mat cmp_nonbase_cases = nullmat(cmp_nonbase_cases) , 0 , J(1, `NAlts', 1)
replace _cmp_ind`cmp_eqno' = $cmp_mprobit_ind_base + _cmp_y`cmp_eqno' + `cmp_eqno' - 1 if `touse' & _cmp_ind`cmp_eqno'==$cmp_mprobit // indicator for first eq holds choice info
forvalues i=`cmp_eqno'/`=`cmp_eqno'+`NAlts'' {
gen byte _mp_cmp_y`i' = _cmp_y`cmp_eqno' == `=`i'+1-`cmp_eqno''
global cmp_y`i' _mp_cmp_y`i'
}
LabelMprobitEq `cmp_eqno' `parse_eqno' 1 `cmp_eqno'
forvalues j=`=`cmp_eqno'+1'/`=`cmp_eqno'+`NAlts'' { // Generate all equations associated with this, the user's one mprobit equation
tempvar ind`j'
global cmp_ind`j' _cmp_ind`j'
gen byte _cmp_ind`j' = $cmp_mprobit*(_cmp_ind`cmp_eqno'>0) if `touse'
LabelMprobitEq `j' `parse_eqno' `j' `cmp_eqno'
foreach macro in x xc xo xe yR id {
global cmp_`macro'`j' ${cmp_`macro'`cmp_eqno'}
}
mat cmp_num_cuts = cmp_num_cuts \ 0
}
// first equation in expanded group is placeholder, for consistency with asmprobit--constant-only and constant=0
constraint free
local _constraints `_constraints' `r(free)'
constraint `r(free)' [${cmp_eq`cmp_eqno'}]_cons
foreach macro in x xc xo xe yR {
global cmp_`macro'`cmp_eqno'
}
}
else {
if "`m_ro'" == "m" {
replace `asmprobit_ind' = `asmprobit_ind' + (${cmp_y`cmp_eqno'}!=0) * `asprobit_eq' if _cmp_ind`cmp_eqno'
replace `asmprobit_dummy_sum' = `asmprobit_dummy_sum' + (${cmp_y`cmp_eqno'}!=0) if _cmp_ind`cmp_eqno'
replace _cmp_ind`cmp_eqno' = 0 if _cmp_ind`first_asprobit_eq' == 0 // exclude obs missing for base case
}
else {
cap assert mod(${cmp_y`cmp_eqno'}, 1)==0 & ${cmp_y`cmp_eqno'}>=0 & ${cmp_y`cmp_eqno'}<=`=maxbyte()-$cmp_roprobit_ind_base' if `touse', fast
if _rc cmp_error 148 "Dependent variables modeled as rank-ordered probit must take integer values between 0 and `=maxbyte()-$cmp_roprobit_ind_base'."
replace _cmp_ind`cmp_eqno' = ${cmp_y`cmp_eqno'} + $cmp_roprobit_ind_base if _cmp_ind`cmp_eqno'
}
local ++asprobit_eq
}
}
else {
if `asprobit_eq' {
if "`m_ro'"=="m" cmp_error 148 "Each indicator in an alternative-specific multinomial probit group must evaluate to $cmp_mprobit ($" "cmp_mprobit) at least once."
else cmp_error 148 "Each indicator in a rank-ordered probit group must evaluate to $cmp_roprobit ($" "cmp_roprobit) at least once."
}
mat cmp_nonbase_cases = nullmat(cmp_nonbase_cases) , 1
}
cap assert ${cmp_y`cmp_eqno'}==. & _cmp_ind`cmp_eqno'!=$cmp_int if `touse', fast
if _rc==0 global cmp_y`cmp_eqno' .
qui replace _cmp_ind`cmp_eqno' = 0 if `touse' & mi(${cmp_y`cmp_eqno'}) & _cmp_ind`cmp_eqno'!=$cmp_int
forvalues i=`cmp_eqno'/`=`cmp_eqno'+`NAlts'*(`asprobit_eq'==0)' { // do once unless expanding non-alt-specific mprobit eq
if `i'==1 mat cmp_fixed_rhos$parse_L = 0
else mat cmp_fixed_rhos$parse_L = (cmp_fixed_rhos$parse_L, J(`i'-1, 1, .)) \ J(1, `i', `FixedRhoFill$parse_L')
// create sig param unless mprobit eq 1-2 or entirely (ordered/fractional) probit or unobserved
cap assert inlist(_cmp_ind`i', $cmp_out, $cmp_probit, $cmp_oprobit, $cmp_missing, $cmp_frac) if `touse', fast
if _rc==0 {
mat cmp_fixed_sigs$parse_L = nullmat(cmp_fixed_sigs$parse_L), 1
forvalues l=1/`=$parse_L-1' {
mat cmp_fixed_sigs`l' = nullmat(cmp_fixed_sigs`l'), .
}
cap assert inlist(_cmp_ind`i', $cmp_out, $cmp_missing, $cmp_oprobit) if `touse', fast
if _rc==0 global cmp_xc`i' nocons
if "${parse_y`parse_eqno'}"=="." noi di _n as txt "Error for ${cmp_eq`parse_eqno'} equation modeled as standard normal (mean 0, variance 1) and constant term set to 0."
}
else if `asprobit_eq'-1==1 | (`NAlts' & `i'==`cmp_eqno') { // 1st eq of m/roprobit. sig=1 for structural, 0 otherwise, all levels
forvalues l=1/$parse_L {
mat cmp_fixed_sigs`l' = nullmat(cmp_fixed_sigs`l'), `structural'
}
}
else if `asprobit_eq'-1==2 | (`NAlts' & `i'==`cmp_eqno'+1) { // 2nd eq of m/roprobit. sig=1 for structural, 2 otherwise, bottom level
mat cmp_fixed_sigs$parse_L = nullmat(cmp_fixed_sigs$parse_L), sqrt(2-`structural')
forvalues l=1/`=$parse_L-1' {
mat cmp_fixed_sigs`l' = nullmat(cmp_fixed_sigs`l'), .
}
}
else {
forvalues l=1/`=$parse_L-1' {
mat cmp_fixed_sigs`l' = nullmat(cmp_fixed_sigs`l'), .
}
if `i'>=`cmp_eqno'+2 & "${parse_iia`parse_eqno'}" != "" { // impose IIA for non-alt-specifc mprobits
mat cmp_fixed_sigs$parse_L = nullmat(cmp_fixed_sigs$parse_L), sqrt(2-`structural')
forvalues j=`=`cmp_eqno'+1'/`=`i'-1' {
mat cmp_fixed_rhos$parse_L[`i',`j'] = cond(`structural', 0, cond($cmpSigXform, atanh(.5), .5))
}
}
else {
if "${cmp_cov$parse_L}" != "exchangeable" local sigparams$parse_L `sigparams$parse_L' /`ln'sig_`i'
mat cmp_fixed_sigs$parse_L = nullmat(cmp_fixed_sigs$parse_L), .
}
}
if "${cmp_x`i'}"=="" & "${cmp_xc`i'}"=="nocons" { // ml doesn't like eqs with no regressors or constant, but they can be OK in gamma models
global cmp_xc`i'
constraint free
local _constraints `_constraints' `r(free)'
constraint `r(free)' [${cmp_eq`i'}]_cons
local lrtest nocons
}
replace _cmp_ind`i' = $cmp_probity1 if `touse' & _cmp_ind`i'==$cmp_probit & `:word 1 of ${cmp_y`i'}' // to streamline likelihood computation split probit samples into y=0 and y!=0
forvalues l=1/`=$parse_L-1' {
if cmp_fixed_sigs`l'[1,`i'] { // suppress RC and RE lists if this is a base case without structural, so sigs=0
global cmp_rc`l'_`i' ${parse_rc`l'_`parse_eqno'}
global cmp_re`l'_`i' ${parse_re`l'_`parse_eqno'}
global cmp_cov`l'_`i' ${parse_cov`l'_`parse_eqno'}
}
local cmp_NumEff`l'_`i': word count ${cmp_rc`l'_`i'} ${cmp_re`l'_`i'}
}
global cmp_cov${parse_L}_`i' unstructured
local cmp_NumEff${parse_L}_`i' 1 // one "random effect" at bottom
global cmp_re${parse_L}_`i' _cons // ditto
global cmp_intreg`i' ${cmp_intreg`cmp_eqno'}
global cmp_truncreg`i' ${cmp_truncreg`cmp_eqno'}
global cmp_Ut`i' ${cmp_Ut`cmp_eqno'}
global cmp_Lt`i' ${cmp_Lt`cmp_eqno'}
if `i'>`cmp_eqno' {
mat cmp_trunceqs = nullmat(cmp_trunceqs), 0
mat cmp_intregeqs = nullmat(cmp_intregeqs), 0
}
}
if `asprobit_eq'==0 local cmp_eqno = `cmp_eqno' + `NAlts'
macro shift
}
replace `touse' = `touse' & `_touse'
global cmp_d `cmp_eqno'
forvalues eq=1/$cmp_d {
global cmp_eq $cmp_eq ${cmp_eq`eq'}
global cmp_Lt $cmp_Lt ${cmp_Lt`eq'}
global cmp_Ut $cmp_Ut ${cmp_Ut`eq'}
global cmp_yL $cmp_yL ${cmp_y`eq'_L}
global cmp_ind $cmp_ind _cmp_ind`eq'
}
mata _mod.setd($cmp_d); _mod.setL($parse_L)
mata _mod.setUtVars("$cmp_Ut"); _mod.setLtVars("$cmp_Lt"); _mod.setyLVars("$cmp_yL"); _mod.setindVars("$cmp_ind")
drop `_touse'
egen byte `_touse' = rowmax($cmp_ind) if `touse'
replace `touse' = 0 if `_touse'==0 | `_touse'==. // drop obs for which all outcomes unobserved
drop `_touse'
global cmpHasGamma 0
tempname GammaINobs GammaI GammaId
mat `GammaI' = I($cmp_d)
mat `GammaINobs' = I($cmp_d)
forvalues eq1=1/$cmp_d {
foreach EndogVar in ${cmp_yR`eq1'} {
local eq2: list posof `"`EndogVar'"' in global(cmp_eq)
if `eq2' {
mat cmpGammaInd = nullmat(cmpGammaInd) \ `eq2',`eq1'
mat `GammaI'[`eq1', `eq2'] = 1
qui count if _cmp_ind`eq2' & `touse' // is the linear functional referred to sometimes unavailable?
mat `GammaINobs'[`eq1', `eq2'] = r(N)>0
global cmp_gammaparams $cmp_gammaparams /gamma`eq1'_`eq2'
global cmpHasGamma = $cmpHasGamma + 1
}
else cmp_error 111 `"Equation `EndogVar' not found."'
}
}
mata _mod.setGammaI(st_matrix("`GammaI'")); _mod.setGammaInd(st_matrix("cmpGammaInd"))
if $cmpHasGamma {
mata st_matrix("`GammaId'", colsum(st_matrix("`GammaI'")))
forvalues eq=1/$cmp_d {
if "${cmp_y`eq'}"=="." & `GammaId'[1,`eq']==1 cmp_error 481 "Coefficients in ${cmp_eq`eq'} equation are unidentified because dependent variable is entirely unobserved and does not appear in any other equation."
}
mat `GammaId' = `GammaINobs'
forvalues eq1=1/`=$cmp_d-2' {
mat `GammaId' = `GammaId' * `GammaINobs'
}
forvalues eq1=1/$cmp_d {
forvalues eq2=1/$cmp_d {
if `eq1' != `eq2' & `GammaId'[`eq1',`eq2'] {
count if _cmp_ind`eq1' & _cmp_ind`eq2'==0
replace _cmp_ind`eq1' = 0 if _cmp_ind`eq1' & _cmp_ind`eq2'==0
if r(N) noi di _n as txt "(" r(N) plural(r(N)," observation") " dropped from ${cmp_eq`eq1'} equation because " cond(r(N)>1,"they are","it is") " unavailable in the ${cmp_eq`eq2'} equation, on which the ${cmp_eq`eq1'} equation depends)"
}
}
}
}
global cmp_tot_cuts 0 // handle cut parameters now, *after* possibly deleting observations because of gamma interdependencies. which can empty a category
forvalues eq=1/$cmp_d {
if cmp_num_cuts[`eq',1] {
GroupCategoricalVar if ${cmp_y`eq'} < . & `touse' & _cmp_ind`eq', predict(`predict') cmp_eqno(`eq')
global cmp_y`eq' _cmp_y`eq'
mat cmp_cat`eq' = r(cat)
local t = colsof(cmp_cat`eq') - 1
mat cmp_num_cuts[`eq',1] = `t'
if $cmp_max_cuts < `t' global cmp_max_cuts = `t'
global cmp_tot_cuts = $cmp_tot_cuts + `t'
forvalues j=1/`t' {
local cutparams `cutparams' /cut_`eq'_`j'
}
}
}
mata _mod.setMaxCuts($cmp_max_cuts)
}
xi, prefix(" ") noomit `i_oprobit_ys'
tempname Eqs
mat `Eqs' = J($cmp_d, $parse_L, 0)
forvalues eq = 1/$cmp_d {
foreach id in ${cmp_id`eq'} {
local l: list posof "`id'" in global(parse_id)
mat `Eqs'[`eq', `l'] = "`id'"=="_n" | cmp_fixed_sigs`l'[1,`eq']>0 // don't simulate REs with variance 0
}
}
mata _mod.setEqs(st_matrix("`Eqs'"))
mat cmp_NumEff = J($parse_L, $cmp_d, 0)
forvalues l=1/$parse_L {
forvalues eq=1/$cmp_d {
mat cmp_NumEff[`l', `eq'] = `cmp_NumEff`l'_`eq''
}
}
mata _mod.setNumEff(st_matrix("cmp_NumEff"))
local technique technique(`technique')
_vce_parse, optlist(Robust oim opg) argoptlist(CLuster) pwallowed(robust cluster oim opg) old: `wgtexp', `robust' cluster(`cluster') vce(`vce')
local vce `r(vceopt)'
local robust `r(robust)'
local cluster `r(cluster)'
markout `touse' `cluster', strok
if 0`hasfrac' & "`cluster'`robust'"=="" {
local vce vce(robust)
noi di as res _n "Note: fractional probit models imply " as inp "vce(robust)" as res "."
}
tokenize $parse_id
forvalues l = 1/`=$parse_L-1' {
mat cmp_fixed_rhos`l' = J($cmp_d, $cmp_d, `FixedRhoFill`l'')
local ids `ids' ``l''
qui egen long _cmp_id`l' = group(`ids') if `touse'
}
forvalues l=1/$parse_L {
forvalues j=1/$cmp_d {
global cmp_rc`l' ${cmp_rc`l'} ${cmp_rc`l'_`j'} ${cmp_re`l'_`j'}
forvalues k=1/`: word count ${cmp_rc`l'_`j'} ${cmp_re`l'_`j'}' {
global cmp_rceq`l' ${cmp_rceq`l'} ${cmp_eq`j'}
}
}
}
if $parse_L == 1 { // for 1-level models, ml/svy will handle weights
if `"$parse_wexpL"' != "" {
tempvar wvar
cap confirm var $parse_wexpL
if _rc qui gen double `wvar' = $parse_wexpL if `touse'
else local wvar $parse_wexpL
local wgtexp [$parse_wtypeL = `wvar']
local awgtexp [aw = `wvar']
markout `touse' `wvar'
}
}
else {
sort _cmp_id*, stable
global parse_wtype$parse_L $parse_wtypeL
global parse_wexp$parse_L $parse_wexpL
forvalues l = 1/$parse_L {
tempvar weight`l'
local cmp_ids `cmp_ids' _cmp_id`l'
if "${parse_wtype`l'}" != "" {
if 0 & "`svy'"!="" cmp_error 101 "weights not allowed with the {bf:svy} option; the {bf:svy} option assumes survey weights were already specified using svyset"
cap confirm var ${parse_wexp`l'}
if _rc qui gen double `weight`l'' = ${parse_wexp`l'} if `touse'
else local weight`l' ${parse_wexp`l'}
global cmp_weight`l' `weight`l''
markout `touse' `weight`l''
replace `touse' = 0 if `weight`l''<=0
if "${parse_wtype`l'}" == "fweight" {
cap assert mod(`weight`l'', 1)==0 if `touse', fast
if _rc cmp_error 401 "Frequency weights must be integers."
}
if "${parse_wtype`l'}" == "pweight" & 0`wcluster' == 0 {
local wcluster 1
if "`cluster'" != "`:word `l' of $parse_id'" {
if "`cluster'`robust'" != "" {
di as res _n "Warning: " as txt `"[pweight = ${parse_wexp`l'}]"' as res " would usually imply " as txt "vce(cluster `:word `l' of $parse_id')."
di as res "Implementing " as txt `"`=cond("`cluster'"=="", "robust", "cluster `cluster'")'"' as res " instead."
}
else {
local vce vce(`=cond(`l'<$parse_L, "cluster `:word `l' of $parse_id'", "robust")')
local lrtest pweight
di as res _n "Note: " as txt `"[pweight = ${parse_wexp`l'}]"' as res " implies `vce'"
}
}
}
if `l' < $parse_L {
tempvar t
qui by `cmp_ids': egen float `t' = mad(`weight`l'') if `touse'
qui assert inlist(`t', 0, .) if `touse', fast
if _rc cmp_error 101 "Weights for level {res}`:word `l' of $parse_id'{err} must be constant within groups."
drop `t'
}
}
}
if "`svy'"!="" {
if "`: char _dta[_svy_wvar]'" != "" local wvar: char _dta[_svy_wvar]
if "`wvar'" != "" {
local wgtexp [pw = `wvar']
local awgtexp [aw = `wvar']
markout `touse' `wvar'
}
}
tokenize $parse_id // rebuild id's in case weights<=0 nix some groups
local ids
qui forvalues l = 1/`=$parse_L-1' {
local ids `ids' ``l''
drop _cmp_id`l'
egen long _cmp_id`l' = group(`ids') if `touse'
}
sort _cmp_id*, stable
}
qui count if `touse'
if r(N)==0 cmp_error 2000 "No observations."
mata _mod.settodo("`lf'"=="")
if "`predict'" != "" {
forvalues l=1/$parse_L {
mat cmp_fixed_rhos`l' = e(fixed_rhos`l')
mat cmpSigScoreInds`l' = e(sig_score_inds`l')
}
global cmp_num_scores = e(num_scores)
mata _mod.setNumREDraws(strtoreal(tokens("`redraws'"))')
constraint drop `_constraints' `initconstraints' `1onlyinitconstraints'
}
mata _mod.setMprobitGroupInds(st_matrix("cmp_mprobit_group_inds" )); _mod.setRoprobitGroupInds(st_matrix("cmp_roprobit_group_inds"))
mata _mod.setNonbaseCases(st_matrix("cmp_nonbase_cases"))
mata _mod.setvNumCuts(st_matrix("cmp_num_cuts")); _mod.settrunceqs(st_matrix("cmp_trunceqs")); _mod.setintregeqs(st_matrix("cmp_intregeqs"))
// /lnsigEx_[lev] accross (ergo within too), exchangeable
// /lnsigEx accross, bottom
// /lnsigEx_[lev]_[eq] within-equation, exchangeable
// /lnsig_[coef]_[lev]_[eq] unstructured
// /lnsig_[eq] bottom level
if "${cmp_cov$parse_L}" == "exchangeable" {
local sigparams$parse_L `sigparams$parse_L' /`ln'sigEx
}
forvalues l=1/`=$parse_L-1' {
if "${cmp_cov`l'}" == "exchangeable" {
local sigparams`l' `sigparams`l'' /`ln'sigEx_`l'
}
else {
forvalues eq=1/$cmp_d {
if cmp_nonbase_cases[1,`eq'] {
if "${cmp_cov`l'_`eq'}" == "exchangeable" {
local sigparams`l' `sigparams`l'' /`ln'sigEx_`l'_`eq'
}
else {
forvalues c=1/`:word count ${cmp_rc`l'_`eq'}' {
local sigparams`l' `sigparams`l'' /`ln'sig_`c'_`l'_`eq'
}
if "${cmp_re`l'_`eq'}"!="" local sigparams`l' `sigparams`l'' /`ln'sig_`l'_`eq'
}
}
}
}
}
// /atanhrhoEx_[lev] across, exchangeable
// /atanhrhoEx across, exchangeable, bottom level
// /atanhrhoEx_[lev]_[eq] within-equation, exchangeable
// /atanhrho_[coef1]_[coef2]_[lev]_[eq] within, unstructured
// /atanhrho_[eq1][eq2] across, bottom level
// /atanhrho_[lev]_[eq1][eq2] across, upper levels, REs on both sides
// /atanhrho_[coef1]_[coef2]_[lev]_[eq1][eq2] across, upper levels, REs not on both sides
forvalues l=$parse_L(-1)1 {
if "${cmp_cov`l'}" == "exchangeable" {
local sigparams`l' `sigparams`l'' /`atanh'rhoEx`=cond(`l'<$parse_L,"_`l'","")'
}
forvalues eq1=1/$cmp_d {
if "${cmp_cov`l'_`eq1'}"=="exchangeable" & cmp_NumEff[`l', `eq1'] & cmp_nonbase_cases[1,`eq1'] {
local sigparams`l' `sigparams`l'' /`atanh'rhoEx_`l'_`eq1'
}
forvalues c1=1/`=cmp_NumEff[`l', `eq1']' {
if "${cmp_cov`l'_`eq1'}"=="unstructured" {
forvalues c2=`=`c1'+1'/`=cmp_NumEff[`l', `eq1']' {
local sigparams`l' `sigparams`l'' /`atanh'rho_`c1'_`c2'_`l'_`eq1'
}
}
forvalues eq2=`=`eq1'+1'/$cmp_d {
if cmp_nonbase_cases[1,`eq1'] & cmp_nonbase_cases[1,`eq2'] {
if cmp_fixed_rhos`l'[`eq2',`eq1']==. & "${cmp_cov`l'}" == "unstructured" {
forvalues c2=1/`=cmp_NumEff[`l', `eq2']' {
local sigparams`l' `sigparams`l'' /`atanh'rho`=cond("`:word `c1' of ${cmp_rc`l'_`eq1'}'`:word `c2' of ${cmp_rc`l'_`eq2'}'"=="","","_`c1'_`c2'")'`_l'_`eq1'`eq2'
}
}
}
else mat cmp_fixed_rhos`l'[`eq2',`eq1'] = 0
}
}
}
local _l _`=`l'-1'
}
forvalues l=1/$parse_L {
local sigparams `sigparams' `sigparams`l''
}
local auxparams `cutparams' `sigparams'
if "`predict'" != "" {
local 0 `predict'
syntax if/, [lnl(varname) scores(varlist) EQuation(string)]
local s = cond(0`e(k_gamma)'`e(k_gamma_reducedform)', "s", "") // for gamma models, make sure to use structural parameter set
tempname hold
_est hold `hold', copy restore
local model `e(model)'
version 11: ml model `:subinstr local model ": . =" ": _cmp_ind1 =", all' if e(sample) & `if', collinear missing // XXX incorporating user's if restriction here will affect results in hierarchical models?? too soon?
mata _mod.settodo("`scores'"!=""); st_local("rc", strofreal(_mod.cmp_init($ML_M)))
if `rc' error `rc'
_est unhold `hold'
mata _lnf = _S = _H = .
mata moptimize_init_userinfo($ML_M, 1, &_mod)
mata (void) cmp_lf1($ML_M, "`scores'"!="", st_matrix("e(b`s')"), _lnf, _S, _H)
if "`lnl'" != "" mata st_view(_H, ., "`lnl'", st_global("ML_samp")); _H[,] = _lnf
else { // scores requested
mata st_view(_H, ., "`scores'", st_global("ML_samp"))
if "`e(resultsform)'" == "reduced" {
di as err "cmp: Won't compute scores on reduced-form results. " _c
if "`c(prefix)'"=="svy" di as err "Try estimating with cmp's svy option instead of the svy prefix." _c
di _n _n
}
// if "`e(resultsform)'" == "reduced" mata _H[,] = _S * ("`equation'" == ""? st_matrix("e(dbr_db)") : st_matrix("e(dbr_db)")[`equation',])'
else mata _H[,] = "`equation'" == ""? _S : _S [,`equation']
}
cmp_clear
exit 0
}
ereturn clear
tempname b cmpInitFull
// Fit individual models before mis-specifed and constant-only ones in case perfect probit predictors shrink some eq samples
// Do InitSearch even if user specifies init() to check for that and to build fully labelled parameter vector for constraint work in Estimate
if "`init'" == "" {
di as res _n "Fitting individual models as starting point for full model fit."
`quietly' di as res "Note: For programming reasons, these initial estimates may deviate from your specification."
`quietly' di as res " For exact fits of each equation alone, run cmp separately on each."
}
`quietly' DoInitSearch InitSearch if `touse' `=cond("`subpop'"!="","& `subpop'","")' `wgtexp', `svy' adjustprobitsample `drop' auxparams(`auxparams') `=cond("`init'" == "", "", "quietly")' mlopts(`mlopts')
mat `cmpInitFull' = r(b)
local ParamsDisplay `r(ParamsDisplay)'
local XVarsAll `r(XVarsAll)'
if "`estimate'" != "" {
mat colnames `cmpInitFull' = `ParamsDisplay'
NoEstimate `cmpInitFull' `wgtexp'
ereturn display
cmp_clear
di as res _n `"Full model not fit. To view the initial coefficient matrix, type or click on {stata "mat list e(b)"}."'
di as res "You can copy and modify this matrix, then pass it back to {cmd:cmp} with the {cmd:init()} option."
exit 0
}
local initconstraints `r(initconstraints)'
local auxparams `r(auxparams)'
global cmp_num_scores = $cmpHasGamma + $cmp_d + `:word count `auxparams''
tempvar t
egen byte `t' = anycount(_cmp_ind*), values(0)
qui replace `touse' = 0 if `t'==$cmp_d
qui count if `touse'
if r(N)==0 cmp_error 2000 "No observations."
drop `t'
tokenize $parse_id
cap drop _cmp_id*
local ids
if $parse_L > 1 {
forvalues l = 1/`=$parse_L-1' {
local ids `ids' ``l''
qui egen long _cmp_id`l' = group(`ids') if `touse' // rebuild these in case whole groups dropped, forcing renumbering
}
sort _cmp_id*, stable
}
forvalues i=1/$cmp_d { // save these for full fit in case they get modified by 1only or meff calls to InitSearch
local cmp_x`i' ${cmp_x`i'}
local cmp_xc`i' ${cmp_xc`i'}
}
if "`meff'" != "" {
di as res _n "Fitting misspecified model."
qui InitSearch if `touse' `=cond("`subpop'"!="","& `subpop'","")', `drop' auxparams(`auxparams') mlopts(`mlopts')
mat `b' = r(b)
Estimate if `touse' `=cond("`subpop'"!="","& `subpop'","")', init(`init') cmpinit(`b') `vce' auxparams(`auxparams') psampling(`psampling') resteps(`steps') `lf' ///
`constraints' _constraints(`_constraints' `initconstraints') `autoconstrain' mlopts(`mlopts') `iterate' `technique' `quietly' redraws(`redraws') paramsdisplay(`r(ParamsDisplay)') `interactive'
if _rc==0 {