5
ComCtrls,Classes, Graphics, ExtCtrls, define_types,{stats,}StatThdsUtil,lesion_pattern,Mat,Math,Distr,Vector;
7
procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp);
12
uses npmform, dialogs;
14
procedure VisualProg(lPos: Integer);
16
MainForm.ProgressBar1.Position := lPos;
22
finalloglik: SingleP0;
23
KxKA1,KxKB1,KxKA,KxKB :TMatrix;
25
Kveci,kVeci1 : TVectori;
26
betak,xbeta,y,pi,ustar,
27
XXx,XXXW2,XXFisher,XXcovs,XXXWPrime,
28
deltahalfs,deltat,delta,covs,x,Fisher,XW2,W,XWprime,Hprime,H,ustarmat,negx: TMatrix;
30
lnCondx,lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx : integer;
31
lPlankImgx: byteP;lOutImgMnx,lSymptomRAx: SingleP;
35
procedure logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean);
36
//todo zero output incase exit
37
//yin = 1..numSubj binary 0/1 values
38
//xin = numSubj*numCond predictors
39
//Chivals = 0..numCond p-values - the 0th Khi-value is the intercept
40
// [0th value will not be computed if ; lComputeIntercept= false]
49
SumY0,SumY1,mx, beta0,loglik,loglikold: double;
50
sumy, n, i,j, k, iter,halfs,lCond,dropCond: integer;
51
variability,firth: boolean;
52
procedure crossprodustar;
56
for row := 1 to k do begin
58
for inc := 1 to ustar.r do
59
ustarmat[row,1] := ustarmat[row,1] + (x[row,inc]*ustar[inc,1]);
66
for inc := 1 to pi.r do
67
ustar[inc,1] := ustar[inc,1]+ H[inc,inc]*(0.5-pi[inc,1]);
69
procedure DiagP2 (var W, P: TMatrix);
74
for inc := 1 to P.r do
75
W[inc,inc] := Power((P[inc,1] * (1-P[inc,1])),0.5) ;
77
procedure ComputeFisher;
83
XWPrime.transpose(XW2);
84
Fisher.mult(XW2,XWPrime);
86
covs.Invert2(KxKA,KxKB,Kvec,Kveci)
87
end; //nested computeFisher
89
procedure computedropdelta;
91
jinc,iinc,ii,jj: integer;
95
//XXXWPrime.copy( XXXW2);
96
//XXXWPrime.transpose;
97
XXXWPrime.transpose(XXXW2);
98
XXFisher.mult(XXXW2,XXXWPrime);
99
XXcovs.copy( XXFisher);
101
XXcovs.Invert2(KxKA1,KxKB1,Kvec1,Kveci1);
104
for iinc := 1 to (k) do begin
105
if iinc <> (dropCond+1) then begin //leave the specified column zeros...
108
for jinc := 1 to (k) do begin
109
if jinc <> (dropCond+1) then begin
111
covs[iinc,jinc] := xxCovs[ii,jj];
117
function firthpenalty: double;
120
//result := 0.5 * ln(abs(Fisher.det));
121
result := 0.5 * ln(abs(Fisher.Det2(KxKA,kVeci,kVec)));
122
end; //nested firthpenalty
123
function ComputeLogLik: double;
128
xbeta.mult(betak,negx);
129
for inc := 1 to n do begin
130
lDenom := (1 + exp( xbeta[inc,1]));
134
pi[inc,1] := 1/lDenom;
139
//if pi[inc,1] <> 1 then
140
result := result+ln(pi[inc,1]);
143
//if pi[inc,1] <> 1 then
144
result := result+ln(1-pi[inc,1]);
146
result := result + firthpenalty;
147
end;//nested ComputeLogLik
149
for i := 0 to (numCond) do
151
if (numSubj < 2) or (numCond < 1) then
153
//ensure there is some variability in the input data...
154
variability := false;
158
if xin^[i] <> xin^[1] then
160
until (i= (numSubj*numCond)) or (variability);
161
if not variability then
162
exit; //no variance in the regressors...
163
variability := false;
167
if y[i,1] <> y[1,1] then
169
until (i= (numSubj)) or (variability);
170
if not variability then
171
exit; //no variance in the dependent variable...
172
dropCond := -1; //initially compute full model, then compute effect of removing individual conditions
177
//beta := TMatrix.Create(n,1);
179
//first row = 1: ell samples have equal weight
182
//next load model into x
185
for i := 1 to n do begin
187
x.M[j,i] := xin^[iter];
189
//WriteMatrix('Observations',y);
190
//WriteMatrix('Model',x);
191
//negx is just sing-swapped - we will generate this as we use it a lot...
193
for i := 1 to n do begin
194
negx.M[j,i] := -x.M[j,i];
196
//now start computations
199
sumy := sumy + round(y[i,1]);
200
if (sumy <= 0) or (sumy >= n) then begin
201
//serious error: no variability. This should have been detected earlier in the procedure when yin was tested for variability
204
beta0 := ln((sumy/n)/(1 - sumy/n));//initial estimate
205
123: //go here for each dropcond
206
if DropCond >= 0 then begin
208
betak.mult( 0) //start with a null model... does not really make sense
211
betak[1,1] := (beta0);
214
if DropCond >= 0 then begin //drop one of the factors...
215
if dropCond <> 0 then begin//include intercept
221
for j := 1 to NumCond do begin
222
if j <> DropCond then begin
225
XXx.M[lCond,i] := x.M[j+1,i];
226
end; //if j <> dropCond
228
end;//if lDropCond >= 0
229
loglik := ComputeLogLik;
233
HPrime.mult(XWPrime,covs);
240
if dropCond >= 0 then // model with dropped factor
242
deltat.mult(covs,ustarmat);
243
delta.transpose(deltat);
244
mx := delta.MatAbsMax/MaxStep;
246
delta.mult(mx);//scale delta
250
while halfs <= maxhs do begin // Half-Steps
251
//fx(iter,halfs,loglik);
252
loglik := ComputeLogLik;
253
deltahalfs.mult(delta,power(2,-halfs));
254
betak.sub(deltahalfs);
255
if (loglik > loglikold) then
259
if delta.MatAbsMax <= epsilon then break;
260
until (iter >= maxit);
261
//fx(DropCond,loglik);
262
//done with this model - record model fit
264
finalloglik^[k] := loglik //full model
266
finalloglik^[DropCond] := loglik; //model with a factor removed
268
if DropCond < numCond then begin
270
if (DropCond = 0) and (not lComputeIntercept) then //only compute intercept model if requested
277
//ResultsForm.Memo1.lines.add (inttostr(j)+' cases have Y=0, '+inttostr(n-j)+' cases have Y=1');
278
if lComputeIntercept then
282
for i := J to (k-1) do begin
283
lZVals^[i] := abs(2*(finalloglik^[i]-finalloglik^[k]));
284
//find direction of effect - does a larger value of the IV predict more zeros or ones
285
lZVals^[i] := pNormalInv(ChiSq(lZVals^[i],1));
286
//we have now computed a Z scores - but Chi is one tailed, so all Z > 0... lets check direction
289
for iter := 1 to n do begin
290
if y[iter,1] = 0 then
291
Sumy0 := Sumy0 + x.M[i+1,iter] //+1: M indexed from 1, ZVal indexed from 0
293
Sumy1 := Sumy1 + x.M[i+1,iter]; //+1 M indexed from 1
297
Sumy0 := Sumy0/(n-sumy);
298
if Sumy0 < Sumy1 then //negative z-scores: damage here predicts performance is BETTER
299
lZVals^[i] := -lZVals^[i];
301
(*if lComputeIntercept then //intercept is the 0th value
302
lChiVals[0] := abs(2*(finalloglik[0]-finalloglik[k]));
303
for i := 1 to (k-1) do //k-1 as this is indexed from 0
304
lChiVals[i] := abs(2*(finalloglik[i]-finalloglik[k])); *)
309
//FirthAnalyzeNoThread (lnCond,lnCrit, lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg);
311
procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp);
312
//calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer);
320
lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern;
321
lPattern: TLesionPattern;
323
lPrevZVals: array [1..knPrevPattern] of SingleP0;
325
lPatternPos,lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer;
328
lnCritLocal := lnCrit;
329
if lnCritLocal < 1 then
331
Getmem(lObs,lImagesCount*sizeof(byte));
332
Getmem(lZVals,(lnCond+1)*sizeof(single));
333
for lPos := 1 to knPrevPattern do
334
Getmem(lPrevZVals[lPos],(lnCond+1)*sizeof(single));
337
y := TMatrix.Create(n,1);
338
GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1);
339
x := TMatrix.Create (k, n);
340
betak:=TMatrix.Create(1,k);
341
covs:=TMatrix.Create(k,k);
342
delta:=TMatrix.Create(1,k);
343
deltahalfs:=TMatrix.Create(1,k);
344
deltat:=TMatrix.Create(k,1);
345
Fisher:=TMatrix.Create(k,k);
346
H:=TMatrix.Create(n,n);
347
HPrime:=TMatrix.Create(n,k);
348
negx:=TMatrix.Create(k,n);
349
pi:=TMatrix.Create(n,1);
350
ustar:=TMatrix.Create(n,1);
351
ustarmat:=TMatrix.create(k,1);
352
W:=TMatrix.Create(n,n);
353
xbeta:=TMatrix.Create(1,n);
354
XW2:=TMatrix.Create(k,n);
355
//XWPrime:=TMatrix.Create(k,n);
356
XWPrime:=TMatrix.Create(n,k);
357
XXcovs:=TMatrix.Create(k-1,k-1);
358
XXFisher:=TMatrix.Create(k-1,k-1);
359
XXx:=TMatrix.Create(k-1,n);
360
XXXW2:=TMatrix.Create(k-1,n);
361
//XXXWPrime:=TMatrix.Create(k-1,n);
362
XXXWPrime := TMatrix.Create ( n, k-1);
363
KxKA := TMatrix.Create(k,k);
364
KxKB := TMatrix.Create(k,k);
365
Kvec := TVector.Create(k);
366
Kveci := TVectori.Create(k);
367
KxKA1 := TMatrix.Create(k-1,k-1);
368
KxKB1 := TMatrix.Create(k-1,k-1);
369
Kvec1 := TVector.Create(k-1);
370
Kveci1 := TVectori.Create(k-1);
372
lPosPct := (lThreadEnd-lThreadStart) div 100;
373
for lPatternPos := 1 to knPrevPattern do
374
lPrevPatternRA[lPatternPos] := EmptyOrder;
376
for lPos2 := lThreadStart to lThreadEnd do begin
377
if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then
378
VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100));
379
lPos2Offset := lPos2+lStartVox-1;
382
for lPos := 1 to lImagesCount do begin
383
if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin
391
y[lPos,1] := 1; //note: lObs indexed from zero!
394
lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count;
395
if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin
396
lPattern := SetOrderX (lObs,lImagesCount);
398
while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do
400
if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin
401
inc(gnVoxTestedRA[lThread]);
402
//logistfx(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false);
403
for lC := 1 to lnCond do
404
lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lPos]^[lC];
405
end else begin //new pattern - need to compute
406
inc(gnVoxTestedRA[lThread]);
407
logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false);
408
for lC := 1 to lnCond do
409
lOutImg^[lC]^[lPos2Offset] := lZvals^[lC];
410
lPrevPatternRA[lPatternPos] := lPattern;
411
for lC := 1 to lnCond do
412
lPrevZVals[lPatternPos]^[lC] := lZvals^[lC];
414
if lPatternPos > knPrevPattern then
418
end; //nlesion > nCritical
420
end; //for each voxel
424
for lPos := 1 to knPrevPattern do
425
freemem(lPrevZVals[lPos]);
460
freemem(finalloglik);
b'\\ No newline at end of file'