subroutine treegrowth(fixweight,maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,DATATYPE,beta1,beta2,&
	beta1len,beta2len,nodenummat,allfval,prunind,Rsplitmat)
	IMPLICIT NONE
	integer,intent(in) :: msize,colnum,levelcount,beta1len,beta2len,maxdepth,minsplit,minbucket
	integer,intent(in) :: datatype(colnum-3)
	double precision,intent(in) :: fixweight,alpha
	double precision,intent(in) :: xydata(msize,colnum),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: Rsplitmat((2**maxdepth)-1,10)
	double precision,intent(out) :: allfval((2**maxdepth)-1)
	integer,intent(out) :: prunind
	integer,intent(out) :: nodenummat(msize,maxdepth)
	double precision splitpval,weightval,weight,weightpval,splitwfval,splitweight,splitmcp,alphamcp
	double precision fval(2),splitfval(2),splitmcppval(2)
	integer nodenum, hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,sizenum,sizer,sizel,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:), splitindvec(:),nodesizesub(:)
	integer,allocatable :: factor_idx_arr(:)
	double precision,allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer,allocatable :: flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	double precision :: splitgroupsum
	logical :: dfvec_set
	double precision,allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),xynodedata(:,:)
	integer, allocatable :: w_subj_map(:), w_si_arr(:), ti_arr(:), w_subj_group(:)
	real(8), allocatable :: w_ygroup(:), w_ytime(:), w_ysubject(:), w_ygrouptime(:,:)
	real(8), allocatable :: w_ygroupcount(:), w_ytimecount(:), w_ysubjectcount(:), w_ygrouptimecount(:,:)
	real(8), allocatable :: w_ytime_sum(:)
	integer :: w_nsubjects, w_timecount, w_max_subj_id, gi, ti, si
	real(8) :: ymean_const, sstotal_const, sstime_const, total_y_sum
	real(8) :: ssgroup, ssgrouptime, sssubject, sserr, ygroup_mean1, ygroup_mean2, gt_mean
	integer, allocatable :: factor_count(:), factor_offset(:), factor_obs(:)
	integer :: obs_i, f, lo, hi, mid
	Rsplitmat(:,:) = 0.0d0
	nodenummat(:,:) = 0
	nodenummat(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2))
	prunind=0
	splitpval = 1d0
	call splitcount(msize, colnum-3, xydata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(msize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	w_timecount = nint(maxval(xydata(:,3)))
	w_max_subj_id = nint(maxval(xydata(:,2)))
	allocate(w_subj_map(w_max_subj_id))
	w_subj_map(:) = 0
	do i = 1, msize
		w_subj_map(nint(xydata(i,2))) = 1
	enddo
	w_nsubjects = 0
	do i = 1, w_max_subj_id
		if (w_subj_map(i) > 0) then
			w_nsubjects = w_nsubjects + 1
			w_subj_map(i) = w_nsubjects
		endif
	enddo
	allocate(w_si_arr(msize), ti_arr(msize), w_subj_group(w_nsubjects))
	allocate(w_ygroup(2), w_ytime(w_timecount), w_ytime_sum(w_timecount))
	allocate(w_ysubject(w_nsubjects), w_ygrouptime(2, w_timecount))
	allocate(w_ygroupcount(2), w_ytimecount(w_timecount))
	allocate(w_ysubjectcount(w_nsubjects), w_ygrouptimecount(2, w_timecount))
	dfvec(1) = 1
	dfvec(2) = w_timecount - 1
	dfvec(3) = w_timecount - 1
	dfvec(4) = w_nsubjects - 2
	dfvec(5) = (w_timecount - 1) * (w_nsubjects - 2)
	dfvec_const = dfvec
	dfvec_set = .true.
	ymean_const = sum(xydata(:,1)) / dble(msize)
	sstotal_const = 0d0
	w_ytime(:) = 0d0; w_ytimecount(:) = 0d0
	w_ysubject(:) = 0d0; w_ysubjectcount(:) = 0d0
	do i = 1, msize
		ti = nint(xydata(i,3))
		si = w_subj_map(nint(xydata(i,2)))
		w_si_arr(i) = si
		ti_arr(i) = ti
		sstotal_const = sstotal_const + (xydata(i,1) - ymean_const)**2
		w_ytime(ti) = w_ytime(ti) + xydata(i,1)
		w_ytimecount(ti) = w_ytimecount(ti) + 1d0
		w_ysubject(si) = w_ysubject(si) + xydata(i,1)
		w_ysubjectcount(si) = w_ysubjectcount(si) + 1d0
	enddo
	w_ytime_sum = w_ytime
	total_y_sum = ymean_const * dble(msize)
	w_ytime = w_ytime / w_ytimecount
	w_ysubject = w_ysubject / w_ysubjectcount
	sstime_const = 0d0
	do ti = 1, w_timecount
		sstime_const = sstime_const + w_ytimecount(ti) * (w_ytime(ti) - ymean_const)**2
	enddo
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		allocate(factor_idx_arr(msize))
		call splitmat(ind1,datatype(ind1-3),xydata,msize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		call dataval(xydata(:,ind1),msize,facvalout,countvec(ind1-3))
		do i = 1, msize
			lo = 1; hi = countvec(ind1-3)
			do while (lo <= hi)
				mid = (lo + hi) / 2
				if (facvalout(mid) == xydata(i,ind1)) then
					factor_idx_arr(i) = mid
					exit
				elseif (xydata(i,ind1) < facvalout(mid)) then
					hi = mid - 1
				else
					lo = mid + 1
				endif
			enddo
		enddo
		allocate(factor_count(countvec(ind1-3)))
		allocate(factor_offset(countvec(ind1-3)+1))
		allocate(factor_obs(msize))
		factor_count(:) = 0
		do i = 1, msize
			f = factor_idx_arr(i)
			factor_count(f) = factor_count(f) + 1
		enddo
		factor_offset(1) = 1
		do f = 2, countvec(ind1-3) + 1
			factor_offset(f) = factor_offset(f-1) + factor_count(f-1)
		enddo
		factor_count(:) = 0
		do i = 1, msize
			f = factor_idx_arr(i)
			factor_count(f) = factor_count(f) + 1
			factor_obs(factor_offset(f) + factor_count(f) - 1) = i
		enddo
		if (datatype(ind1-3) == 1) then
			w_ygroup(1) = 0d0; w_ygroup(2) = total_y_sum
			w_ygroupcount(1) = 0d0; w_ygroupcount(2) = dble(msize)
			w_ygrouptime(1,:) = 0d0; w_ygrouptime(2,:) = w_ytime_sum(:)
			w_ygrouptimecount(1,:) = 0d0; w_ygrouptimecount(2,:) = w_ytimecount(:)
			w_subj_group(:) = 2
			do ind2 = 1,splitnum(ind1-3)
				indcou = indcou + 1
				indmat(indcou,1) = ind1
				indmat(indcou,2) = ind2
				do j = factor_offset(ind2), factor_offset(ind2+1) - 1
					obs_i = factor_obs(j)
					w_ygroup(2) = w_ygroup(2) - xydata(obs_i,1)
					w_ygroup(1) = w_ygroup(1) + xydata(obs_i,1)
					w_ygroupcount(2) = w_ygroupcount(2) - 1d0
					w_ygroupcount(1) = w_ygroupcount(1) + 1d0
					ti = ti_arr(obs_i)
					w_ygrouptime(2,ti) = w_ygrouptime(2,ti) - xydata(obs_i,1)
					w_ygrouptime(1,ti) = w_ygrouptime(1,ti) + xydata(obs_i,1)
					w_ygrouptimecount(2,ti) = w_ygrouptimecount(2,ti) - 1d0
					w_ygrouptimecount(1,ti) = w_ygrouptimecount(1,ti) + 1d0
					w_subj_group(w_si_arr(obs_i)) = 1
				enddo
				ygroup_mean1 = w_ygroup(1) / w_ygroupcount(1)
				ygroup_mean2 = w_ygroup(2) / w_ygroupcount(2)
				ssgroup = w_ygroupcount(1) * (ygroup_mean1 - ymean_const)**2 + &
				          w_ygroupcount(2) * (ygroup_mean2 - ymean_const)**2
				ssgrouptime = 0d0
				do ti = 1, w_timecount
					gt_mean = w_ygrouptime(1,ti) / w_ygrouptimecount(1,ti)
					ssgrouptime = ssgrouptime + w_ygrouptimecount(1,ti) * &
					    (gt_mean - ygroup_mean1 - w_ytime(ti) + ymean_const)**2
					gt_mean = w_ygrouptime(2,ti) / w_ygrouptimecount(2,ti)
					ssgrouptime = ssgrouptime + w_ygrouptimecount(2,ti) * &
					    (gt_mean - ygroup_mean2 - w_ytime(ti) + ymean_const)**2
				enddo
				sssubject = 0d0
				do si = 1, w_nsubjects
					if (w_subj_group(si) == 1) then
						sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean1)**2
					else
						sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean2)**2
					endif
				enddo
				sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
				fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
				fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
				fval_cache(indcou,1) = fval(1)
				fval_cache(indcou,2) = fval(2)
				groupsum_cache(indcou) = w_ygroupcount(2)
				if(fixweight == -1.0d0) then
					do wcou = 0,10
						weightval = 0.1d0 * dble(wcou)
						wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					enddo
				else
					weightval = fixweight
					wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				endif
			enddo
		else
			do ind2 = 1,splitnum(ind1-3)
				indcou = indcou + 1
				indmat(indcou,1) = ind1
				indmat(indcou,2) = ind2
				w_ygroup(:) = 0d0; w_ygroupcount(:) = 0d0
				w_ygrouptime(:,:) = 0d0; w_ygrouptimecount(:,:) = 0d0
				do i = 1, msize
					gi = splitindmat(ind2, factor_idx_arr(i)) + 1
					w_ygroup(gi) = w_ygroup(gi) + xydata(i,1)
					w_ygroupcount(gi) = w_ygroupcount(gi) + 1d0
					ti = ti_arr(i)
					w_ygrouptime(gi,ti) = w_ygrouptime(gi,ti) + xydata(i,1)
					w_ygrouptimecount(gi,ti) = w_ygrouptimecount(gi,ti) + 1d0
					w_subj_group(w_si_arr(i)) = gi
				enddo
				w_ygroup = w_ygroup / w_ygroupcount
				w_ygrouptime = w_ygrouptime / w_ygrouptimecount
				ssgroup = w_ygroupcount(1) * (w_ygroup(1) - ymean_const)**2 + &
				          w_ygroupcount(2) * (w_ygroup(2) - ymean_const)**2
				ssgrouptime = 0d0
				do ti = 1, w_timecount
					do gi = 1, 2
						ssgrouptime = ssgrouptime + w_ygrouptimecount(gi,ti) * &
						    (w_ygrouptime(gi,ti) - w_ygroup(gi) - w_ytime(ti) + ymean_const)**2
					enddo
				enddo
				sssubject = 0d0
				do si = 1, w_nsubjects
					sssubject = sssubject + w_ysubjectcount(si) * &
					    (w_ysubject(si) - w_ygroup(w_subj_group(si)))**2
				enddo
				sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
				fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
				fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
				fval_cache(indcou,1) = fval(1)
				fval_cache(indcou,2) = fval(2)
				groupsum_cache(indcou) = w_ygroupcount(2)
				if(fixweight == -1.0d0) then
					do wcou = 0,10
						weightval = 0.1d0 * dble(wcou)
						wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					enddo
				else
					weightval = fixweight
					wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				endif
			enddo
		endif
		deallocate(splitindmat,facvalout,factor_idx_arr)
		deallocate(factor_count, factor_offset, factor_obs)
	enddo
	deallocate(w_subj_map, w_si_arr, ti_arr, w_subj_group)
	deallocate(w_ygroup, w_ytime, w_ytime_sum, w_ysubject, w_ygrouptime)
	deallocate(w_ygroupcount, w_ytimecount, w_ysubjectcount, w_ygrouptimecount)
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call weightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(msize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = ind1vec(weightind+1)
				splitind2 = ind2vec(weightind+1)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call splitmat(ind1,datatype(ind1-3),xydata,msize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call splitdata(splitindmat(ind2,:),countvec(ind1-3),xydata,msize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call weightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(msize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = ind1vec(1)
			splitind2 = ind2vec(1)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call splitmat(ind1,datatype(ind1-3),xydata,msize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call splitdata(splitindmat(ind2,:),countvec(ind1-3),xydata,msize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			deallocate(splitindmat,facvalout)
		endif
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call weightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call weightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(.not. allocated(splitfacval)) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum <= dble(levelcount*minbucket) .or. &
	(dble(msize) - splitgroupsum) <= dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002	
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	Rsplitmat(1,1) =dble(nodenum)
	Rsplitmat(1,2) = splitweight
	Rsplitmat(1,3) = 1d0-splitweight
	Rsplitmat(1,4) = splitind1
	Rsplitmat(1,5) = splitind2
	Rsplitmat(1,6) = splitfval(1)
	Rsplitmat(1,7) = splitfval(2)
	Rsplitmat(1,8) = splitweight*splitfval(1) + (1-splitweight)*splitfval(2)
	Rsplitmat(1,9) = splitpval
	Rsplitmat(1,10) = splitmcp
	sizenum = size(splitfacval)
	call nodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummat,sizel,sizer)
	nodesize(1) = sizel
	nodesize(2) = sizer
	deallocate(anovadata)
	allfval(1) = splitwfval
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			if(allocated(splitfacval)) deallocate(splitfacval, splitindvec)
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call nodedatanumber(xydata,msize,colnum,nodenum,hierarchy,maxdepth,nodenummat,nodesize(nodeloop),xynodedata)
			call splitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			indcou = 0
			w_timecount = nint(maxval(xynodedata(:,3)))
			w_max_subj_id = nint(maxval(xynodedata(:,2)))
			allocate(w_subj_map(w_max_subj_id))
			w_subj_map(:) = 0
			do i = 1, nodesize(nodeloop)
				w_subj_map(nint(xynodedata(i,2))) = 1
			enddo
			w_nsubjects = 0
			do i = 1, w_max_subj_id
				if (w_subj_map(i) > 0) then
					w_nsubjects = w_nsubjects + 1
					w_subj_map(i) = w_nsubjects
				endif
			enddo
			allocate(w_si_arr(nodesize(nodeloop)), ti_arr(nodesize(nodeloop)), w_subj_group(w_nsubjects))
			allocate(w_ygroup(2), w_ytime(w_timecount), w_ytime_sum(w_timecount))
			allocate(w_ysubject(w_nsubjects), w_ygrouptime(2, w_timecount))
			allocate(w_ygroupcount(2), w_ytimecount(w_timecount))
			allocate(w_ysubjectcount(w_nsubjects), w_ygrouptimecount(2, w_timecount))
			dfvec(1) = 1
			dfvec(2) = w_timecount - 1
			dfvec(3) = w_timecount - 1
			dfvec(4) = w_nsubjects - 2
			dfvec(5) = (w_timecount - 1) * (w_nsubjects - 2)
			dfvec_const = dfvec
			dfvec_set = .true.
			ymean_const = sum(xynodedata(:,1)) / dble(nodesize(nodeloop))
			sstotal_const = 0d0
			w_ytime(:) = 0d0; w_ytimecount(:) = 0d0
			w_ysubject(:) = 0d0; w_ysubjectcount(:) = 0d0
			do i = 1, nodesize(nodeloop)
				ti = nint(xynodedata(i,3))
				si = w_subj_map(nint(xynodedata(i,2)))
				w_si_arr(i) = si
				ti_arr(i) = ti
				sstotal_const = sstotal_const + (xynodedata(i,1) - ymean_const)**2
				w_ytime(ti) = w_ytime(ti) + xynodedata(i,1)
				w_ytimecount(ti) = w_ytimecount(ti) + 1d0
				w_ysubject(si) = w_ysubject(si) + xynodedata(i,1)
				w_ysubjectcount(si) = w_ysubjectcount(si) + 1d0
			enddo
			w_ytime_sum = w_ytime
			total_y_sum = ymean_const * dble(nodesize(nodeloop))
			w_ytime = w_ytime / w_ytimecount
			w_ysubject = w_ysubject / w_ysubjectcount
			sstime_const = 0d0
			do ti = 1, w_timecount
				sstime_const = sstime_const + w_ytimecount(ti) * (w_ytime(ti) - ymean_const)**2
			enddo
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) deallocate(splitindmat)
				allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				if(allocated(facvalout)) deallocate(facvalout)
				allocate(facvalout(countvec(ind1-3)))
				allocate(factor_idx_arr(nodesize(nodeloop)))
				call splitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
				call dataval(xynodedata(:,ind1),nodesize(nodeloop),facvalout,countvec(ind1-3))
				do i = 1, nodesize(nodeloop)
					lo = 1; hi = countvec(ind1-3)
					do while (lo <= hi)
						mid = (lo + hi) / 2
						if (facvalout(mid) == xynodedata(i,ind1)) then
							factor_idx_arr(i) = mid
							exit
						elseif (xynodedata(i,ind1) < facvalout(mid)) then
							hi = mid - 1
						else
							lo = mid + 1
						endif
					enddo
				enddo
				allocate(factor_count(countvec(ind1-3)))
				allocate(factor_offset(countvec(ind1-3)+1))
				allocate(factor_obs(nodesize(nodeloop)))
				factor_count(:) = 0
				do i = 1, nodesize(nodeloop)
					f = factor_idx_arr(i)
					factor_count(f) = factor_count(f) + 1
				enddo
				factor_offset(1) = 1
				do f = 2, countvec(ind1-3) + 1
					factor_offset(f) = factor_offset(f-1) + factor_count(f-1)
				enddo
				factor_count(:) = 0
				do i = 1, nodesize(nodeloop)
					f = factor_idx_arr(i)
					factor_count(f) = factor_count(f) + 1
					factor_obs(factor_offset(f) + factor_count(f) - 1) = i
				enddo
				if (datatype(ind1-3) == 1) then
					w_ygroup(1) = 0d0; w_ygroup(2) = total_y_sum
					w_ygroupcount(1) = 0d0; w_ygroupcount(2) = dble(nodesize(nodeloop))
					w_ygrouptime(1,:) = 0d0; w_ygrouptime(2,:) = w_ytime_sum(:)
					w_ygrouptimecount(1,:) = 0d0; w_ygrouptimecount(2,:) = w_ytimecount(:)
					w_subj_group(:) = 2
					do ind2 = 1,splitnum(ind1-3)
						indcou = indcou + 1
						indmat(indcou,1) = ind1
						indmat(indcou,2) = ind2
						do j = factor_offset(ind2), factor_offset(ind2+1) - 1
							obs_i = factor_obs(j)
							w_ygroup(2) = w_ygroup(2) - xynodedata(obs_i,1)
							w_ygroup(1) = w_ygroup(1) + xynodedata(obs_i,1)
							w_ygroupcount(2) = w_ygroupcount(2) - 1d0
							w_ygroupcount(1) = w_ygroupcount(1) + 1d0
							ti = ti_arr(obs_i)
							w_ygrouptime(2,ti) = w_ygrouptime(2,ti) - xynodedata(obs_i,1)
							w_ygrouptime(1,ti) = w_ygrouptime(1,ti) + xynodedata(obs_i,1)
							w_ygrouptimecount(2,ti) = w_ygrouptimecount(2,ti) - 1d0
							w_ygrouptimecount(1,ti) = w_ygrouptimecount(1,ti) + 1d0
							w_subj_group(w_si_arr(obs_i)) = 1
						enddo
						ygroup_mean1 = w_ygroup(1) / w_ygroupcount(1)
						ygroup_mean2 = w_ygroup(2) / w_ygroupcount(2)
						ssgroup = w_ygroupcount(1) * (ygroup_mean1 - ymean_const)**2 + &
						          w_ygroupcount(2) * (ygroup_mean2 - ymean_const)**2
						ssgrouptime = 0d0
						do ti = 1, w_timecount
							gt_mean = w_ygrouptime(1,ti) / w_ygrouptimecount(1,ti)
							ssgrouptime = ssgrouptime + w_ygrouptimecount(1,ti) * &
							    (gt_mean - ygroup_mean1 - w_ytime(ti) + ymean_const)**2
							gt_mean = w_ygrouptime(2,ti) / w_ygrouptimecount(2,ti)
							ssgrouptime = ssgrouptime + w_ygrouptimecount(2,ti) * &
							    (gt_mean - ygroup_mean2 - w_ytime(ti) + ymean_const)**2
						enddo
						sssubject = 0d0
						do si = 1, w_nsubjects
							if (w_subj_group(si) == 1) then
								sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean1)**2
							else
								sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean2)**2
							endif
						enddo
						sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
						fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
						fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
						fval_cache(indcou,1) = fval(1)
						fval_cache(indcou,2) = fval(2)
						groupsum_cache(indcou) = w_ygroupcount(2)
						if(fixweight == -1.0d0) then
							do wcou = 0,10
								weightval = 0.1d0 * dble(wcou)
								wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
							enddo
						else
							weightval = fixweight
							wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						endif
					enddo
				else
					do ind2 = 1,splitnum(ind1-3)
						indcou = indcou + 1
						indmat(indcou,1) = ind1
						indmat(indcou,2) = ind2
						w_ygroup(:) = 0d0; w_ygroupcount(:) = 0d0
						w_ygrouptime(:,:) = 0d0; w_ygrouptimecount(:,:) = 0d0
						do i = 1, nodesize(nodeloop)
							gi = splitindmat(ind2, factor_idx_arr(i)) + 1
							w_ygroup(gi) = w_ygroup(gi) + xynodedata(i,1)
							w_ygroupcount(gi) = w_ygroupcount(gi) + 1d0
							ti = ti_arr(i)
							w_ygrouptime(gi,ti) = w_ygrouptime(gi,ti) + xynodedata(i,1)
							w_ygrouptimecount(gi,ti) = w_ygrouptimecount(gi,ti) + 1d0
							w_subj_group(w_si_arr(i)) = gi
						enddo
						w_ygroup = w_ygroup / w_ygroupcount
						w_ygrouptime = w_ygrouptime / w_ygrouptimecount
						ssgroup = w_ygroupcount(1) * (w_ygroup(1) - ymean_const)**2 + &
						          w_ygroupcount(2) * (w_ygroup(2) - ymean_const)**2
						ssgrouptime = 0d0
						do ti = 1, w_timecount
							do gi = 1, 2
								ssgrouptime = ssgrouptime + w_ygrouptimecount(gi,ti) * &
								    (w_ygrouptime(gi,ti) - w_ygroup(gi) - w_ytime(ti) + ymean_const)**2
							enddo
						enddo
						sssubject = 0d0
						do si = 1, w_nsubjects
							sssubject = sssubject + w_ysubjectcount(si) * &
							    (w_ysubject(si) - w_ygroup(w_subj_group(si)))**2
						enddo
						sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
						fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
						fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
						fval_cache(indcou,1) = fval(1)
						fval_cache(indcou,2) = fval(2)
						groupsum_cache(indcou) = w_ygroupcount(2)
						if(fixweight == -1.0d0) then
							do wcou = 0,10
								weightval = 0.1d0 * dble(wcou)
								wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
							enddo
						else
							weightval = fixweight
							wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						endif
					enddo
				endif
				deallocate(splitindmat,facvalout,factor_idx_arr)
				deallocate(factor_count, factor_offset, factor_obs)
2000			continue
			enddo
			deallocate(w_subj_map, w_si_arr, ti_arr, w_subj_group)
			deallocate(w_ygroup, w_ytime, w_ytime_sum, w_ysubject, w_ygrouptime)
			deallocate(w_ygroupcount, w_ytimecount, w_ysubjectcount, w_ygrouptimecount)
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call weightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = ind1vec(weightind+1)
						splitind2 = ind2vec(weightind+1)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call splitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call splitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call weightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = ind1vec(1)
					splitind2 = ind2vec(1)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call splitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call splitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					deallocate(splitindmat,facvalout)
				endif
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call weightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call weightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(.not. allocated(splitfacval)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum <= dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) <= dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			sizenum = size(splitfacval)
			call nodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummat,sizel,sizer)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			Rsplitmat(nodenum,1) =dble(nodenum)
			Rsplitmat(nodenum,2) = splitweight
			Rsplitmat(nodenum,3) = 1d0-splitweight
			Rsplitmat(nodenum,4) = splitind1
			Rsplitmat(nodenum,5) = splitind2
			Rsplitmat(nodenum,6) = splitfval(1)
			Rsplitmat(nodenum,7) = splitfval(2)
			Rsplitmat(nodenum,8) = splitweight*splitfval(1) + (1-splitweight)*splitfval(2)
			Rsplitmat(nodenum,9) = splitpval
			Rsplitmat(nodenum,10) = splitmcp
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache)
			if(allocated(groupsum_cache)) deallocate(groupsum_cache)
			if(allocated(flat_idx_vec)) deallocate(flat_idx_vec)
			deallocate(anovadata,xynodedata)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize)
		allocate(nodesize(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		deallocate(nodesizesub)
	enddo
2003 continue
	deallocate(nodesize)
2002 continue
	if(allocated(fval_cache)) deallocate(fval_cache)
	if(allocated(groupsum_cache)) deallocate(groupsum_cache)
	if(allocated(flat_idx_vec)) deallocate(flat_idx_vec)
end subroutine treegrowth
subroutine datasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call datasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine datasum
recursive subroutine datasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call datasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call datasort(datavec, j+1, msize)
	endif
	return
end subroutine datasort
subroutine dataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call datasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine dataval
subroutine datasumval(datavec, msize, facsum, facval)
	IMPLICIT NONE
	integer, intent(in) :: msize
	double precision, intent(in) :: datavec(msize)
	integer, intent(out) :: facsum
	double precision, intent(out) :: facval(msize)
	double precision :: datavecsub(msize)
	integer :: j, k
	datavecsub(:) = datavec(:)
	call datasort(datavecsub, 1, msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2, msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
	facsum = k
end subroutine datasumval
subroutine splitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	double precision, intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	double precision datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call datasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call datasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine splitcount
subroutine splitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
	end subroutine splitmat
subroutine splitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	double precision, intent(in) :: xydata(msize,colnum)
	double precision, intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	double precision facval(countvec)
	call dataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
				exit
			endif
		enddo
	enddo
end subroutine splitdata
subroutine repANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	double precision, intent(in) :: anovadata(msize,4)
	double precision, intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	double precision ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	double precision ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	double precision, allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	double precision, allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine repANOVA
subroutine weightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	double precision, intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: weightpval
	double precision DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	double precision xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call pfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call pfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call demethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE weightedpval
subroutine pfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	double precision,parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	double precision,intent(in)::a,b,eps,df1,df2,beta
	double precision,intent(out)::s
	double precision res,zval
	double precision inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine pfdist
subroutine demethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	double precision,intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    double precision,intent(out)::s
	integer,parameter::kmin=3, kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    double precision yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call demethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call demethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine demethod
subroutine demethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    double precision,intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    double precision,intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    double precision inv_weight
    double precision const_factor, df_ratio1, df_ratio2
    double precision df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    double precision v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine demethod2
subroutine weightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	double precision,intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	double precision,intent(out) :: res
	double precision zval,form1,form2,form3,form4,form5,form6,form7,form8,form9
	double precision inv_weight, inv_beta1, inv_beta2
	double precision df_ratio1, df_ratio2, df11_half, df21_half
	double precision df12_sum_half, df22_sum_half
	inv_weight = 1d0 - weight
	inv_beta1 = 1d0 / beta1
	inv_beta2 = 1d0 / beta2
	df_ratio1 = df11/df12
	df_ratio2 = df21/df22
	df11_half = df11/2d0
	df21_half = df21/2d0
	df12_sum_half = (df11+df12)/2d0
	df22_sum_half = (df21+df22)/2d0
	zval = (z-(inv_weight*v))/weight
	form1 = 1d0 / weight
	form2 = inv_beta1
	form3 = df_ratio1**df11_half
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+(df_ratio1*zval))**df12_sum_half
	form6 = inv_beta2
	form7 = df_ratio2**df21_half
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+(df_ratio2*v))**df22_sum_half
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine weightfformula
subroutine nodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	double precision, intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(inout) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer
	integer i,j
	sizel=0
	sizer=0
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummat(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummat(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine nodenumber
subroutine nodedatanumber(xydata,msize,colnum,nodenum,hierarchy,maxdepth,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize,maxdepth
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine nodedatanumber
subroutine cvtreepruning(prunind,msize,alpha,gamma,cv,maxdepth,nodenummat,allfval,allgammaval)
	IMPLICIT NONE
	integer,intent(in) :: prunind,msize,cv,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	double precision,intent(in) :: alpha,gamma,allfval((2**maxdepth)-1)
	double precision,intent(out) :: allgammaval((2**(maxdepth-1))-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision minghval,allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:)
	allgammaval(:) = 0d0
	if(prunind == 1 .or. alpha < 1d0 .or. gamma >= 0d0 .or. cv == -1) then
		goto 3001
	endif
	call cvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call cvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	allocate(nodenummatnew(msize,maxdepth),nodenummatnewsub(msize,maxdepth))
	call cvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	deallocate(nodenummatnewsub)
	allgammaval(2) = minghval
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call cvterminalnodecount(nodenummatnew,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call cvweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allocate(nodenummatnewsub(msize,maxdepth))
		call cvpruntreemat(nodenummatnew,maxdepth,msize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub)
		allgammaval(prunloop+1) = minghval
	enddo
3001 continue
end subroutine cvtreepruning
subroutine cvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine cvterminalnodecount
subroutine cvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine cvweaknode
subroutine cvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine cvpruntreemat
subroutine crossvalidation(gamma,alpha,cv,xydata,msize,colnum,Ksplit,levelcount,maxdepth,beta1,beta2,&
beta1len,beta2len,minbucket,minsplit,fixweight,datatype,allgammaval,bestgammaval,r2cvvalmean,iseed)
	IMPLICIT NONE
	integer,intent(in) :: cv,msize,colnum,Ksplit,maxdepth,levelcount,beta1len,beta2len,minbucket,minsplit
	integer,intent(in) :: datatype(colnum-3)
	integer,intent(in) :: iseed
	real(8),intent(in) :: alpha,gamma,fixweight
	real(8),intent(in) :: beta1(beta1len),beta2(beta2len),allgammaval((2**(maxdepth-1))-1)
	real(8),intent(in) :: xydata(msize,colnum)
	real(8),intent(out) :: bestgammaval,r2cvvalmean
	integer, allocatable :: cvind(:),cvsize(:)
	integer, allocatable ::  nodenummat(:,:), prunenodenummat(:,:),nodenummattest(:,:),prunenodenummattest(:,:)
	real(8), allocatable :: meangammacv(:),meangammar2cv(:)
	real(8), allocatable :: gammacvmat(:,:),traindata(:,:),testdata(:,:),gammar2cvmat(:,:)
	integer cvloop,traindatasize,testdatasize,prunind,i
	real(8) allfval((2**maxdepth)-1),gammacv((2**(maxdepth-1))-1),r2cvvalvec(ksplit),gammar2cv((2**(maxdepth-1))-1)
	real(8) r2cvval,maxgammasub
	allocate(cvind(msize),cvsize(Ksplit),gammacvmat(ksplit,(2**(maxdepth-1))-1))
	allocate(gammar2cvmat(ksplit,(2**(maxdepth-1))-1),meangammacv((2**(maxdepth-1))-1))
	allocate(meangammar2cv((2**(maxdepth-1))-1))
	call cvdata(XYDATA,msize,colnum,Ksplit,levelcount,cvind,cvsize,iseed)
	meangammacv(:) = 0d0
	meangammar2cv(:) = 0d0
	gammacvmat(:,:) = 0d0
	gammar2cvmat(:,:) = 0d0
	r2cvvalvec(:) = 0d0
	allfval(:) = 0d0
	gammacv(:) = 0d0
	r2cvvalvec(:) = 0d0
	gammar2cv(:) = 0d0
	do cvloop = 1,Ksplit
		traindatasize = ((sum(cvsize)-cvsize(cvloop))*levelcount)
		testdatasize = (cvsize(cvloop)*levelcount)
		allocate(traindata(traindatasize,colnum),testdata(testdatasize,colnum))
		allocate(nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth))
		call cvdatachoice(XYDATA,msize,colnum,Ksplit,levelcount,cvloop,cvind,cvsize,traindata,testdata)
		call cvtreegrowth(traindatasize,testdatasize,traindata,testdata,nodenummattest,fixweight,&
		maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,datatype,beta1,beta2,beta1len,&
		beta2len,nodenummat,allfval,prunind)
		if(alpha < 1d0 .and. gamma < 0d0 .and. cv == -1) then
			call R2CV(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
			nodenummattest,testdatasize,maxdepth,r2cvval)
			r2cvvalvec(cvloop) = r2cvval
			bestgammaval = -1d0
		endif
		if(alpha == 1d0 .and. gamma >= 0d0 .and. cv == -1) then
			allocate(prunenodenummat(traindatasize,maxdepth),prunenodenummattest(testdatasize,maxdepth))
			call cvgammatreepruning(prunind,traindatasize,testdatasize,gamma,maxdepth,nodenummat,&
			nodenummattest,allfval,prunenodenummat,prunenodenummattest)
			call R2CV(traindata,traindatasize,prunenodenummat,testdata,colnum,levelcount,&
			prunenodenummattest,testdatasize,maxdepth,r2cvval)
			r2cvvalvec(cvloop) = r2cvval
			deallocate(prunenodenummattest,prunenodenummat)
			bestgammaval = gamma
		endif
		if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
			call cvbesttreepruning(traindatasize,testdatasize,maxdepth,nodenummat,nodenummattest,allfval,&
			levelcount,colnum,traindata,testdata,allgammaval,gammacv,gammar2cv)
			gammacvmat(cvloop,:) = gammacv(:)
			gammar2cvmat(cvloop,:) = gammar2cv(:)
		endif
		deallocate(traindata,testdata,nodenummat,nodenummattest)
	enddo
	if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
		do i = 1,size(allgammaval)
			meangammacv(i) = sum(gammacvmat(:,i))
			meangammar2cv(i) = sum(gammar2cvmat(:,i))
			if(meangammacv(i) > 0 .and. meangammar2cv(i) > 0) then
				meangammacv(i) = meangammacv(i) / dble(msize/levelcount)
				meangammar2cv(i) = meangammar2cv(i) / dble(ksplit)
			else
				meangammacv(i) = -1d0
			endif
		enddo
		maxgammasub = maxval(meangammacv) + 1d0
		do i = 1,size(meangammacv)
			if(meangammacv(i) < maxgammasub .and. meangammacv(i) >= 0d0) then
				bestgammaval = allgammaval(i)
				maxgammasub = meangammacv(i)
				r2cvvalmean = meangammar2cv(i)
			endif
		enddo
	else
		r2cvvalmean=sum(r2cvvalvec)/dble(ksplit)
	endif
end subroutine crossvalidation
subroutine cvdata(XYDATA,msize,colnum,Ksplit,levelcount,cvind,cvsize,iseed)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,levelcount
	integer, intent(in) :: iseed
	real(8), intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: cvind(msize), cvsize(Ksplit)
	integer i,subnum, randval, cvsizecou(Ksplit)
	integer, allocatable :: cvindsub(:)
	real(8) randvalsub,ii
	integer :: seed_size, seed_i
	integer, allocatable :: seed_array(:)
	call random_seed(size=seed_size)
	allocate(seed_array(seed_size))
	do seed_i = 1, seed_size
		seed_array(seed_i) = iseed + (seed_i - 1) * 37
	enddo
	call random_seed(put=seed_array)
	deallocate(seed_array)
	subnum = msize/levelcount
	cvsize(:) = subnum/Ksplit
	do i = 1,(subnum - sum(cvsize))
		cvsize(i) = cvsize(i) + 1
	enddo
	allocate(cvindsub(subnum))
	cvsizecou(:) = cvsize(:)
	do i = 1,subnum
		do
		    call random_number(randvalsub)
			randval = int(randvalsub * dble(Ksplit)) + 1
			if(cvsizecou(randval) > 0)then
				cvsizecou(randval) = cvsizecou(randval) - 1
				cvindsub(i) = randval
				exit
			endif
		enddo
	enddo
	do i = 1,subnum
		cvind((levelcount*(i-1)+1):(levelcount*i)) = cvindsub(i)
	enddo
end subroutine cvdata
subroutine cvdatachoice(XYDATA,msize,colnum,Ksplit,levelcount,testind,cvind,cvsize,traindata,testdata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,testind,levelcount
	real(8), intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: cvind(msize),cvsize(Ksplit)
	real(8), intent(out) :: traindata(((sum(cvsize)-cvsize(testind))*levelcount),colnum),testdata((cvsize(testind)*levelcount),colnum)
	integer i,jtrain,jtest,subnum
	subnum = msize/levelcount
	jtest = 1
	jtrain = 1
	do i = 1,subnum
		if(cvind(((i-1)*levelcount)+1) == testind) then
			testdata((levelcount*(jtest-1)+1):(levelcount*jtest),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtest = jtest + 1
		else
			traindata((levelcount*(jtrain-1)+1):(levelcount*jtrain),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtrain = jtrain + 1
		endif
	enddo
end subroutine cvdatachoice
subroutine cvtreegrowth(traindatasize,testdatasize,traindata,testdata,nodenummattest,fixweight,&
maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,datatype,beta1,beta2,beta1len,&
beta2len,nodenummat,allfval,prunind)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,beta1len,beta2len,levelcount,minsplit,minbucket,msize
	integer, intent(in) :: datatype(colnum-3)
	real(8), intent(in) :: fixweight,alpha
	real(8), intent(in) :: traindata(traindatasize,colnum),beta1(beta1len),beta2(beta2len)
	real(8), intent(in) :: xydata(msize,colnum),testdata(testdatasize,colnum)
	integer, intent(out) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	integer,intent(out) :: prunind
	real(8),intent(out) :: allfval((2**maxdepth)-1)
	integer nodenum,hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,separatecou,separateint,sizenum
	integer sizel,sizer,sizeltest,sizertest,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5)
	real(8) splitmcp,splitpval,weightval,weight,weightpval,splitweight,splitwfval,separatesp,alphamcp
	real(8) fval(2),splitfval(2),splitmcppval(2)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:),splitindvec(:),nodesizetest(:)
	integer,allocatable :: nodesizesub(:),nodesizesubtest(:)
	real(8), allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),separateval(:)
	real(8), allocatable :: xynodedata(:,:),xynodedatatest(:,:)
	real(8), allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer, allocatable :: factor_idx(:), flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	real(8) :: splitgroupsum
	logical :: dfvec_set
	integer, allocatable :: w_subj_map(:), w_si_arr(:), w_subj_group(:)
	real(8), allocatable :: w_ygroup(:), w_ytime(:), w_ysubject(:), w_ygrouptime(:,:)
	real(8), allocatable :: w_ygroupcount(:), w_ytimecount(:), w_ysubjectcount(:), w_ygrouptimecount(:,:)
	integer :: w_nsubjects, w_timecount, w_max_subj_id, gi, ti, si
	real(8) :: ymean_const, sstotal_const, sstime_const
	real(8) :: ssgroup, ssgrouptime, sssubject, sserr
	integer, allocatable :: ti_arr(:), factor_count(:), factor_offset(:), factor_obs(:)
	real(8) :: total_y_sum, ygroup_mean1, ygroup_mean2, gt_mean
	real(8), allocatable :: w_ytime_sum(:)
	integer :: obs_i, f, lo, hi, mid
	nodenummat(:,:) = 0
	nodenummat(:,1) = 1
	nodenummattest(:,:) = 0
	nodenummattest(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2),nodesizetest(2))
	prunind=0
	splitpval = 1d0
	call cvsplitcount(traindatasize, colnum-3, traindata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(traindatasize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	w_timecount = nint(maxval(traindata(:,3)))
	w_max_subj_id = nint(maxval(traindata(:,2)))
	allocate(w_subj_map(w_max_subj_id))
	w_subj_map(:) = 0
	do i = 1, traindatasize
		w_subj_map(nint(traindata(i,2))) = 1
	enddo
	w_nsubjects = 0
	do i = 1, w_max_subj_id
		if (w_subj_map(i) > 0) then
			w_nsubjects = w_nsubjects + 1
			w_subj_map(i) = w_nsubjects
		endif
	enddo
	allocate(w_si_arr(traindatasize), w_ygroup(2), w_ytime(w_timecount))
	allocate(w_ysubject(w_nsubjects), w_ygrouptime(2, w_timecount))
	allocate(w_ygroupcount(2), w_ytimecount(w_timecount))
	allocate(w_ysubjectcount(w_nsubjects), w_ygrouptimecount(2, w_timecount))
	allocate(w_subj_group(w_nsubjects))
	allocate(ti_arr(traindatasize), w_ytime_sum(w_timecount))
	dfvec_const(1) = 1
	dfvec_const(2) = w_timecount - 1
	dfvec_const(3) = w_timecount - 1
	dfvec_const(4) = w_nsubjects - 2
	dfvec_const(5) = (w_timecount - 1) * (w_nsubjects - 2)
	dfvec_set = .true.
	ymean_const = sum(traindata(:,1)) / dble(traindatasize)
	sstotal_const = 0d0
	w_ytime(:) = 0d0; w_ytimecount(:) = 0d0
	w_ysubject(:) = 0d0; w_ysubjectcount(:) = 0d0
	do i = 1, traindatasize
		ti = nint(traindata(i,3))
		si = w_subj_map(nint(traindata(i,2)))
		w_si_arr(i) = si
		ti_arr(i) = ti
		sstotal_const = sstotal_const + (traindata(i,1) - ymean_const)**2
		w_ytime(ti) = w_ytime(ti) + traindata(i,1)
		w_ytimecount(ti) = w_ytimecount(ti) + 1d0
		w_ysubject(si) = w_ysubject(si) + traindata(i,1)
		w_ysubjectcount(si) = w_ysubjectcount(si) + 1d0
	enddo
	w_ytime_sum = w_ytime
	total_y_sum = ymean_const * dble(traindatasize)
	w_ytime = w_ytime / w_ytimecount
	w_ysubject = w_ysubject / w_ysubjectcount
	sstime_const = 0d0
	do ti = 1, w_timecount
		sstime_const = sstime_const + w_ytimecount(ti) * (w_ytime(ti) - ymean_const)**2
	enddo
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		allocate(factor_idx(traindatasize))
		call cvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		call cvdataval(traindata(:,ind1),traindatasize,facvalout,countvec(ind1-3))
		do i = 1, traindatasize
			lo = 1; hi = countvec(ind1-3)
			do while (lo <= hi)
				mid = (lo + hi) / 2
				if (facvalout(mid) == traindata(i,ind1)) then
					factor_idx(i) = mid
					exit
				elseif (traindata(i,ind1) < facvalout(mid)) then
					hi = mid - 1
				else
					lo = mid + 1
				endif
			enddo
		enddo
		allocate(factor_count(countvec(ind1-3)))
		allocate(factor_offset(countvec(ind1-3)+1))
		allocate(factor_obs(traindatasize))
		factor_count(:) = 0
		do i = 1, traindatasize
			f = factor_idx(i)
			factor_count(f) = factor_count(f) + 1
		enddo
		factor_offset(1) = 1
		do f = 2, countvec(ind1-3) + 1
			factor_offset(f) = factor_offset(f-1) + factor_count(f-1)
		enddo
		factor_count(:) = 0
		do i = 1, traindatasize
			f = factor_idx(i)
			factor_count(f) = factor_count(f) + 1
			factor_obs(factor_offset(f) + factor_count(f) - 1) = i
		enddo
		if (datatype(ind1-3) == 1) then
			w_ygroup(1) = 0d0; w_ygroup(2) = total_y_sum
			w_ygroupcount(1) = 0d0; w_ygroupcount(2) = dble(traindatasize)
			w_ygrouptime(1,:) = 0d0; w_ygrouptime(2,:) = w_ytime_sum(:)
			w_ygrouptimecount(1,:) = 0d0; w_ygrouptimecount(2,:) = w_ytimecount(:)
			w_subj_group(:) = 2
			do ind2 = 1,splitnum(ind1-3)
				indcou = indcou + 1
				indmat(indcou,1) = ind1
				indmat(indcou,2) = ind2
				do j = factor_offset(ind2), factor_offset(ind2+1) - 1
					obs_i = factor_obs(j)
					w_ygroup(2) = w_ygroup(2) - traindata(obs_i,1)
					w_ygroup(1) = w_ygroup(1) + traindata(obs_i,1)
					w_ygroupcount(2) = w_ygroupcount(2) - 1d0
					w_ygroupcount(1) = w_ygroupcount(1) + 1d0
					ti = ti_arr(obs_i)
					w_ygrouptime(2,ti) = w_ygrouptime(2,ti) - traindata(obs_i,1)
					w_ygrouptime(1,ti) = w_ygrouptime(1,ti) + traindata(obs_i,1)
					w_ygrouptimecount(2,ti) = w_ygrouptimecount(2,ti) - 1d0
					w_ygrouptimecount(1,ti) = w_ygrouptimecount(1,ti) + 1d0
					w_subj_group(w_si_arr(obs_i)) = 1
				enddo
				ygroup_mean1 = w_ygroup(1) / w_ygroupcount(1)
				ygroup_mean2 = w_ygroup(2) / w_ygroupcount(2)
				ssgroup = w_ygroupcount(1) * (ygroup_mean1 - ymean_const)**2 + &
				          w_ygroupcount(2) * (ygroup_mean2 - ymean_const)**2
				ssgrouptime = 0d0
				do ti = 1, w_timecount
					gt_mean = w_ygrouptime(1,ti) / w_ygrouptimecount(1,ti)
					ssgrouptime = ssgrouptime + w_ygrouptimecount(1,ti) * &
					    (gt_mean - ygroup_mean1 - w_ytime(ti) + ymean_const)**2
					gt_mean = w_ygrouptime(2,ti) / w_ygrouptimecount(2,ti)
					ssgrouptime = ssgrouptime + w_ygrouptimecount(2,ti) * &
					    (gt_mean - ygroup_mean2 - w_ytime(ti) + ymean_const)**2
				enddo
				sssubject = 0d0
				do si = 1, w_nsubjects
					if (w_subj_group(si) == 1) then
						sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean1)**2
					else
						sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean2)**2
					endif
				enddo
				sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
				fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
				fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
				fval_cache(indcou,1) = fval(1)
				fval_cache(indcou,2) = fval(2)
				groupsum_cache(indcou) = w_ygroupcount(2)
				if(fixweight == -1.0d0) then
					do wcou = 0,10
						weightval = 0.1d0 * dble(wcou)
						wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					enddo
				else
					weightval = fixweight
					wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				endif
			enddo
		else
			do ind2 = 1,splitnum(ind1-3)
				indcou = indcou + 1
				indmat(indcou,1) = ind1
				indmat(indcou,2) = ind2
				w_ygroup(:) = 0d0; w_ygroupcount(:) = 0d0
				w_ygrouptime(:,:) = 0d0; w_ygrouptimecount(:,:) = 0d0
				do i = 1, traindatasize
					gi = splitindmat(ind2, factor_idx(i)) + 1
					w_ygroup(gi) = w_ygroup(gi) + traindata(i,1)
					w_ygroupcount(gi) = w_ygroupcount(gi) + 1d0
					ti = ti_arr(i)
					w_ygrouptime(gi,ti) = w_ygrouptime(gi,ti) + traindata(i,1)
					w_ygrouptimecount(gi,ti) = w_ygrouptimecount(gi,ti) + 1d0
					w_subj_group(w_si_arr(i)) = gi
				enddo
				w_ygroup = w_ygroup / w_ygroupcount
				w_ygrouptime = w_ygrouptime / w_ygrouptimecount
				ssgroup = w_ygroupcount(1) * (w_ygroup(1) - ymean_const)**2 + &
				          w_ygroupcount(2) * (w_ygroup(2) - ymean_const)**2
				ssgrouptime = 0d0
				do ti = 1, w_timecount
					do gi = 1, 2
						ssgrouptime = ssgrouptime + w_ygrouptimecount(gi,ti) * &
						    (w_ygrouptime(gi,ti) - w_ygroup(gi) - w_ytime(ti) + ymean_const)**2
					enddo
				enddo
				sssubject = 0d0
				do si = 1, w_nsubjects
					sssubject = sssubject + w_ysubjectcount(si) * &
					    (w_ysubject(si) - w_ygroup(w_subj_group(si)))**2
				enddo
				sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
				fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
				fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
				fval_cache(indcou,1) = fval(1)
				fval_cache(indcou,2) = fval(2)
				groupsum_cache(indcou) = w_ygroupcount(2)
				if(fixweight == -1.0d0) then
					do wcou = 0,10
						weightval = 0.1d0 * dble(wcou)
						wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					enddo
				else
					weightval = fixweight
					wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				endif
			enddo
		endif
		deallocate(splitindmat,facvalout,factor_idx)
		deallocate(factor_count, factor_offset, factor_obs)
	enddo
	deallocate(w_subj_map, w_si_arr, w_ygroup, w_ytime, w_ysubject, w_ygrouptime)
	deallocate(w_ygroupcount, w_ytimecount, w_ysubjectcount, w_ygrouptimecount, w_subj_group)
	deallocate(ti_arr, w_ytime_sum)
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call cvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = ind1vec(weightind+1)
				splitind2 = ind2vec(weightind+1)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call cvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call cvsplitdata(splitindmat(ind2,:),countvec(ind1-3),traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call cvdatasum(xydata(:,splitind1),msize,separatecou)
				allocate(separateval(separatecou))
				call cvdataval(xydata(:,splitind1),msize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call cvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = ind1vec(1)
			splitind2 = ind2vec(1)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call cvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call cvsplitdata(splitindmat(ind2,:),countvec(ind1-3),traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call cvdatasum(xydata(:,splitind1),msize,separatecou)
				allocate(separateval(separatecou))
				call cvdataval(xydata(:,splitind1),msize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
			 			separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call cvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call cvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(.not. allocated(splitfacval)) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum < dble(levelcount*minbucket) .or. &
	(dble(traindatasize) - splitgroupsum) < dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002	
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	sizenum = size(splitfacval)
	call cvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummat,sizel,sizer)
	call cvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummattest,sizeltest,sizertest)
	nodesize(1) = sizel
	nodesize(2) = sizer
	nodesizetest(1) = sizeltest
	nodesizetest(2) = sizertest
	deallocate(anovadata)
	allfval(1) = splitwfval
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4),xynodedatatest(nodesizetest(nodeloop),colnum))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call cvnodedata(traindata,traindatasize,colnum,nodenum,hierarchy,maxdepth,nodenummat,nodesize(nodeloop),xynodedata)
			call cvnodedata(testdata,testdatasize,colnum,nodenum,hierarchy,maxdepth,nodenummattest,nodesizetest(nodeloop),xynodedatatest)
			call cvsplitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			indcou = 0
			w_timecount = nint(maxval(xynodedata(:,3)))
			w_max_subj_id = nint(maxval(xynodedata(:,2)))
			allocate(w_subj_map(w_max_subj_id))
			w_subj_map(:) = 0
			do i = 1, nodesize(nodeloop)
				w_subj_map(nint(xynodedata(i,2))) = 1
			enddo
			w_nsubjects = 0
			do i = 1, w_max_subj_id
				if (w_subj_map(i) > 0) then
					w_nsubjects = w_nsubjects + 1
					w_subj_map(i) = w_nsubjects
				endif
			enddo
			allocate(w_si_arr(nodesize(nodeloop)), w_ygroup(2), w_ytime(w_timecount))
			allocate(w_ysubject(w_nsubjects), w_ygrouptime(2, w_timecount))
			allocate(w_ygroupcount(2), w_ytimecount(w_timecount))
			allocate(w_ysubjectcount(w_nsubjects), w_ygrouptimecount(2, w_timecount))
			allocate(w_subj_group(w_nsubjects))
			allocate(ti_arr(nodesize(nodeloop)), w_ytime_sum(w_timecount))
			dfvec_const(1) = 1
			dfvec_const(2) = w_timecount - 1
			dfvec_const(3) = w_timecount - 1
			dfvec_const(4) = w_nsubjects - 2
			dfvec_const(5) = (w_timecount - 1) * (w_nsubjects - 2)
			dfvec_set = .true.
			ymean_const = sum(xynodedata(:,1)) / dble(nodesize(nodeloop))
			sstotal_const = 0d0
			w_ytime(:) = 0d0; w_ytimecount(:) = 0d0
			w_ysubject(:) = 0d0; w_ysubjectcount(:) = 0d0
			do i = 1, nodesize(nodeloop)
				ti = nint(xynodedata(i,3))
				si = w_subj_map(nint(xynodedata(i,2)))
				w_si_arr(i) = si
				ti_arr(i) = ti
				sstotal_const = sstotal_const + (xynodedata(i,1) - ymean_const)**2
				w_ytime(ti) = w_ytime(ti) + xynodedata(i,1)
				w_ytimecount(ti) = w_ytimecount(ti) + 1d0
				w_ysubject(si) = w_ysubject(si) + xynodedata(i,1)
				w_ysubjectcount(si) = w_ysubjectcount(si) + 1d0
			enddo
			w_ytime_sum = w_ytime
			total_y_sum = ymean_const * dble(nodesize(nodeloop))
			w_ytime = w_ytime / w_ytimecount
			w_ysubject = w_ysubject / w_ysubjectcount
			sstime_const = 0d0
			do ti = 1, w_timecount
				sstime_const = sstime_const + w_ytimecount(ti) * (w_ytime(ti) - ymean_const)**2
			enddo
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) then
					deallocate(splitindmat)
				endif
				allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				if(allocated(facvalout)) then
					deallocate(facvalout)
				endif
				allocate(facvalout(countvec(ind1-3)))
				allocate(factor_idx(nodesize(nodeloop)))
				call cvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
				call cvdataval(xynodedata(:,ind1),nodesize(nodeloop),facvalout,countvec(ind1-3))
				do i = 1, nodesize(nodeloop)
					lo = 1; hi = countvec(ind1-3)
					do while (lo <= hi)
						mid = (lo + hi) / 2
						if (facvalout(mid) == xynodedata(i,ind1)) then
							factor_idx(i) = mid
							exit
						elseif (xynodedata(i,ind1) < facvalout(mid)) then
							hi = mid - 1
						else
							lo = mid + 1
						endif
					enddo
				enddo
				allocate(factor_count(countvec(ind1-3)))
				allocate(factor_offset(countvec(ind1-3)+1))
				allocate(factor_obs(nodesize(nodeloop)))
				factor_count(:) = 0
				do i = 1, nodesize(nodeloop)
					f = factor_idx(i)
					factor_count(f) = factor_count(f) + 1
				enddo
				factor_offset(1) = 1
				do f = 2, countvec(ind1-3) + 1
					factor_offset(f) = factor_offset(f-1) + factor_count(f-1)
				enddo
				factor_count(:) = 0
				do i = 1, nodesize(nodeloop)
					f = factor_idx(i)
					factor_count(f) = factor_count(f) + 1
					factor_obs(factor_offset(f) + factor_count(f) - 1) = i
				enddo
				if (datatype(ind1-3) == 1) then
					w_ygroup(1) = 0d0; w_ygroup(2) = total_y_sum
					w_ygroupcount(1) = 0d0; w_ygroupcount(2) = dble(nodesize(nodeloop))
					w_ygrouptime(1,:) = 0d0; w_ygrouptime(2,:) = w_ytime_sum(:)
					w_ygrouptimecount(1,:) = 0d0; w_ygrouptimecount(2,:) = w_ytimecount(:)
					w_subj_group(:) = 2
					do ind2 = 1,splitnum(ind1-3)
						indcou = indcou + 1
						indmat(indcou,1) = ind1
						indmat(indcou,2) = ind2
						do j = factor_offset(ind2), factor_offset(ind2+1) - 1
							obs_i = factor_obs(j)
							w_ygroup(2) = w_ygroup(2) - xynodedata(obs_i,1)
							w_ygroup(1) = w_ygroup(1) + xynodedata(obs_i,1)
							w_ygroupcount(2) = w_ygroupcount(2) - 1d0
							w_ygroupcount(1) = w_ygroupcount(1) + 1d0
							ti = ti_arr(obs_i)
							w_ygrouptime(2,ti) = w_ygrouptime(2,ti) - xynodedata(obs_i,1)
							w_ygrouptime(1,ti) = w_ygrouptime(1,ti) + xynodedata(obs_i,1)
							w_ygrouptimecount(2,ti) = w_ygrouptimecount(2,ti) - 1d0
							w_ygrouptimecount(1,ti) = w_ygrouptimecount(1,ti) + 1d0
							w_subj_group(w_si_arr(obs_i)) = 1
						enddo
						ygroup_mean1 = w_ygroup(1) / w_ygroupcount(1)
						ygroup_mean2 = w_ygroup(2) / w_ygroupcount(2)
						ssgroup = w_ygroupcount(1) * (ygroup_mean1 - ymean_const)**2 + &
						          w_ygroupcount(2) * (ygroup_mean2 - ymean_const)**2
						ssgrouptime = 0d0
						do ti = 1, w_timecount
							gt_mean = w_ygrouptime(1,ti) / w_ygrouptimecount(1,ti)
							ssgrouptime = ssgrouptime + w_ygrouptimecount(1,ti) * &
							    (gt_mean - ygroup_mean1 - w_ytime(ti) + ymean_const)**2
							gt_mean = w_ygrouptime(2,ti) / w_ygrouptimecount(2,ti)
							ssgrouptime = ssgrouptime + w_ygrouptimecount(2,ti) * &
							    (gt_mean - ygroup_mean2 - w_ytime(ti) + ymean_const)**2
						enddo
						sssubject = 0d0
						do si = 1, w_nsubjects
							if (w_subj_group(si) == 1) then
								sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean1)**2
							else
								sssubject = sssubject + w_ysubjectcount(si) * (w_ysubject(si) - ygroup_mean2)**2
							endif
						enddo
						sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
						fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
						fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
						fval_cache(indcou,1) = fval(1)
						fval_cache(indcou,2) = fval(2)
						groupsum_cache(indcou) = w_ygroupcount(2)
						if(fixweight == -1.0d0) then
							do wcou = 0,10
								weightval = 0.1d0 * dble(wcou)
								wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
							enddo
						else
							weightval = fixweight
							wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						endif
					enddo
				else
					do ind2 = 1,splitnum(ind1-3)
						indcou = indcou + 1
						indmat(indcou,1) = ind1
						indmat(indcou,2) = ind2
						w_ygroup(:) = 0d0; w_ygroupcount(:) = 0d0
						w_ygrouptime(:,:) = 0d0; w_ygrouptimecount(:,:) = 0d0
						do i = 1, nodesize(nodeloop)
							gi = splitindmat(ind2, factor_idx(i)) + 1
							w_ygroup(gi) = w_ygroup(gi) + xynodedata(i,1)
							w_ygroupcount(gi) = w_ygroupcount(gi) + 1d0
							ti = ti_arr(i)
							w_ygrouptime(gi,ti) = w_ygrouptime(gi,ti) + xynodedata(i,1)
							w_ygrouptimecount(gi,ti) = w_ygrouptimecount(gi,ti) + 1d0
							w_subj_group(w_si_arr(i)) = gi
						enddo
						w_ygroup = w_ygroup / w_ygroupcount
						w_ygrouptime = w_ygrouptime / w_ygrouptimecount
						ssgroup = w_ygroupcount(1) * (w_ygroup(1) - ymean_const)**2 + &
						          w_ygroupcount(2) * (w_ygroup(2) - ymean_const)**2
						ssgrouptime = 0d0
						do ti = 1, w_timecount
							do gi = 1, 2
								ssgrouptime = ssgrouptime + w_ygrouptimecount(gi,ti) * &
								    (w_ygrouptime(gi,ti) - w_ygroup(gi) - w_ytime(ti) + ymean_const)**2
							enddo
						enddo
						sssubject = 0d0
						do si = 1, w_nsubjects
							sssubject = sssubject + w_ysubjectcount(si) * &
							    (w_ysubject(si) - w_ygroup(w_subj_group(si)))**2
						enddo
						sserr = sstotal_const - ssgroup - sstime_const - ssgrouptime - sssubject
						fval(1) = (ssgroup / dble(dfvec_const(1))) / (sssubject / dble(dfvec_const(4)))
						fval(2) = (ssgrouptime / dble(dfvec_const(3))) / (sserr / dble(dfvec_const(5)))
						fval_cache(indcou,1) = fval(1)
						fval_cache(indcou,2) = fval(2)
						groupsum_cache(indcou) = w_ygroupcount(2)
						if(fixweight == -1.0d0) then
							do wcou = 0,10
								weightval = 0.1d0 * dble(wcou)
								wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
							enddo
						else
							weightval = fixweight
							wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						endif
					enddo
				endif
				deallocate(splitindmat,facvalout,factor_idx)
				deallocate(factor_count, factor_offset, factor_obs)
2000			continue
			enddo
			deallocate(w_subj_map, w_si_arr, w_subj_group, w_ygroup, w_ytime, w_ysubject, w_ygrouptime)
			deallocate(w_ygroupcount, w_ytimecount, w_ysubjectcount, w_ygrouptimecount)
			deallocate(ti_arr, w_ytime_sum)
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call cvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = ind1vec(weightind+1)
						splitind2 = ind2vec(weightind+1)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call cvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call cvsplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call cvdatasum(xydata(:,splitind1),msize,separatecou)
						allocate(separateval(separatecou))
						call cvdataval(xydata(:,splitind1),msize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call cvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = ind1vec(1)
					splitind2 = ind2vec(1)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call cvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call cvsplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call cvdatasum(xydata(:,splitind1),msize,separatecou)
						allocate(separateval(separatecou))
						call cvdataval(xydata(:,splitind1),msize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call cvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call cvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(.not. allocated(splitfacval)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum < dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) < dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001	
			endif
			deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			if(.not. allocated(nodesizesubtest)) then
				allocate(nodesizesubtest(2**hierarchy))
				nodesizesubtest(:) = 0
			endif
			sizenum = size(splitfacval)
			call cvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummat,sizel,sizer)
			call cvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummattest,sizeltest,sizertest)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			nodesizesubtest(2*nodeloop-1) = sizeltest
			nodesizesubtest(2*nodeloop) = sizertest
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache)
			if(allocated(groupsum_cache)) deallocate(groupsum_cache)
			if(allocated(flat_idx_vec)) deallocate(flat_idx_vec)
			if(allocated(factor_idx)) deallocate(factor_idx)
			if(allocated(w_subj_map)) deallocate(w_subj_map)
			if(allocated(w_si_arr)) deallocate(w_si_arr)
			if(allocated(w_ygroup)) deallocate(w_ygroup)
			if(allocated(w_ytime)) deallocate(w_ytime)
			if(allocated(w_ysubject)) deallocate(w_ysubject)
			if(allocated(w_ygrouptime)) deallocate(w_ygrouptime)
			if(allocated(w_ygroupcount)) deallocate(w_ygroupcount)
			if(allocated(w_ytimecount)) deallocate(w_ytimecount)
			if(allocated(w_ysubjectcount)) deallocate(w_ysubjectcount)
			if(allocated(w_ygrouptimecount)) deallocate(w_ygrouptimecount)
			deallocate(anovadata,xynodedata,xynodedatatest)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize,nodesizetest)
		allocate(nodesize(2**hierarchy),nodesizetest(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		nodesizetest(:) = nodesizesubtest(:)
		deallocate(nodesizesub,nodesizesubtest)
	enddo
2003 continue
	deallocate(nodesize,nodesizetest)
2002 continue
end subroutine cvtreegrowth
subroutine cvsplitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	real(8), intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	real(8) datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call cvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call cvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine cvsplitcount
subroutine cvdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	real(8),intent(in) :: datavec(msize)
	real(8) datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call cvdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine cvdatasum
recursive subroutine cvdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	real(8),intent(inout)::datavec(msize)
	real(8) x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call cvdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call cvdatasort(datavec, j+1, msize)
	endif
	return
end subroutine cvdatasort
subroutine cvdatasumval(datavec, msize, facsum, facval)
	IMPLICIT NONE
	integer, intent(in) :: msize
	real(8), intent(in) :: datavec(msize)
	integer, intent(out) :: facsum
	real(8), intent(out) :: facval(msize)
	real(8) :: datavecsub(msize)
	integer :: j, k
	datavecsub(:) = datavec(:)
	call cvdatasort(datavecsub, 1, msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2, msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
	facsum = k
end subroutine cvdatasumval
subroutine cvsplitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	real(8), intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
end subroutine cvsplitmat
subroutine cvsplitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	real(8), intent(in) :: xydata(msize,colnum)
	real(8), intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	real(8) facval(countvec)
	call cvdataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
				exit
			endif
		enddo
	enddo
end subroutine cvsplitdata
subroutine cvrepANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	real(8), intent(in) :: anovadata(msize,4)
	real(8), intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	real(8) ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	real(8) ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	real(8), allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	real(8), allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine cvrepANOVA
subroutine cvrepANOVA_fast(msize, anovadata, fval, dfvec, &
	subj_map, nsubjects, timecount, max_subj_id, &
	si_arr, ygroup, ytime, ysubject, ygrouptime, &
	ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
	IMPLICIT NONE
	integer, intent(in) :: msize, nsubjects, timecount, max_subj_id
	real(8), intent(in) :: anovadata(msize,4)
	real(8), intent(out) :: fval(2)
	integer, intent(out) :: dfvec(5)
	integer, intent(in) :: subj_map(max_subj_id)
	integer, intent(inout) :: si_arr(msize)
	real(8), intent(inout) :: ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2,timecount)
	real(8), intent(inout) :: ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2,timecount)
	integer :: i, gi, ti, si
	real(8) :: ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr, ms(5)
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
end subroutine cvrepANOVA_fast
subroutine cvweightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	real(8), intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	real(8), intent(out) :: weightpval
	REAL(8) DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	real(8) xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call cvpfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call cvpfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call cvdemethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE cvweightedpval
subroutine cvpfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	real(8),parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	real(8),intent(in)::a,b,eps,df1,df2,beta
	real(8),intent(out)::s
	real(8) res,zval
	real(8) inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	real(8) h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine cvpfdist
subroutine cvdemethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	real(8),intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    real(8),intent(out)::s
	integer,parameter::kmin=3, kmax=8
	real(8),parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    real(8) yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call cvdemethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call cvdemethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine cvdemethod
subroutine cvdemethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    real(8),intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    real(8),intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	real(8),parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    real(8) h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    real(8) inv_weight
    real(8) const_factor, df_ratio1, df_ratio2
    real(8) df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    real(8) v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine cvdemethod2
subroutine cvweightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	real(8),intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	real(8),intent(out) :: res
	real(8) zval,form1,form2,form3,form4,form5,form6,form7,form8,form9
	real(8) inv_weight, inv_beta1, inv_beta2
	real(8) df_ratio1, df_ratio2, df11_half, df21_half
	real(8) df12_sum_half, df22_sum_half
	inv_weight = 1d0 - weight
	inv_beta1 = 1d0 / beta1
	inv_beta2 = 1d0 / beta2
	df_ratio1 = df11/df12
	df_ratio2 = df21/df22
	df11_half = df11/2d0
	df21_half = df21/2d0
	df12_sum_half = (df11+df12)/2d0
	df22_sum_half = (df21+df22)/2d0
	zval = (z-(inv_weight*v))/weight
	form1 = 1d0 / weight
	form2 = inv_beta1
	form3 = df_ratio1**df11_half
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+(df_ratio1*zval))**df12_sum_half
	form6 = inv_beta2
	form7 = df_ratio2**df21_half
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+(df_ratio2*v))**df22_sum_half
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine cvweightfformula
subroutine cvdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	real(8),intent(in) :: datavec(msize)
	real(8) datavecsub(msize)
	real(8), intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call cvdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine cvdataval
subroutine cvnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	real(8), intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(inout) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer
	integer i,j
	sizel=0
	sizer=0
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummat(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummat(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine cvnodenumber
subroutine cvnodedata(xydata,msize,colnum,nodenum,hierarchy,maxdepth,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize,maxdepth
	real(8), intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	real(8), intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine cvnodedata
subroutine R2CV(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
nodenummattest,testdatasize,maxdepth,r2cvval)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,levelcount
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	real(8), intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	real(8), intent(out) :: r2cvval
	real(8), allocatable :: timepred(:,:),r2cvnumsub(:,:), timepredcou(:,:)
	real(8) r2cvnum,r2cvden,ymean
	integer i,j,k,l,maxactive_depth,nidx,tidx
	allocate(timepred(((2**maxdepth)-1),levelcount),r2cvnumsub(((2**maxdepth)-1),levelcount))
	allocate(timepredcou(((2**maxdepth)-1),levelcount))
	timepred(:,:) = 0d0
	r2cvnumsub(:,:) = 0d0
	timepredcou(:,:) = 0d0
	maxactive_depth = 0
	do i = 1,maxdepth
		if(sum(nodenummat(:,i)) == 0) exit
		maxactive_depth = i
	enddo
	do j = 1,traindatasize
		tidx = int(traindata(j,3))
		do i = maxactive_depth, 1, -1
			nidx = nodenummat(j,i)
			if(nidx > 0) then
				if(i == maxactive_depth .or. nodenummat(j,i+1) == 0) then
					timepred(nidx,tidx) = timepred(nidx,tidx) + traindata(j,1)
					timepredcou(nidx,tidx) = timepredcou(nidx,tidx) + 1d0
				endif
				exit
			endif
		enddo
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	ymean = sum(testdata(:,1))/dble(testdatasize)
	r2cvnum = 0d0
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j=1,maxdepth
				if(2**(j-1) <= i .and. i < 2**j) then
					k = j
					exit
				endif
			enddo
			do l = 1,testdatasize
				if(nodenummattest(l,k) == i) then
					r2cvnumsub(i,int(testdata(l,3))) = r2cvnumsub(i,int(testdata(l,3))) + ((testdata(l,1) - timepred(i,int(testdata(l,3))))**2)
				endif
			enddo
		endif
	enddo
	r2cvnum = sum(r2cvnumsub)
	r2cvden = 0d0
	do i = 1,testdatasize
		r2cvden = r2cvden + ((testdata(i,1) - ymean) * (testdata(i,1) - ymean))
	enddo
	r2cvval = 1d0-(r2cvnum/r2cvden)
	deallocate(timepred,r2cvnumsub,timepredcou)
end subroutine R2CV
subroutine cvgammatreepruning(prunind,traindatasize,testdatasize,gamma,maxdepth,nodenummat,nodenummattest,&
allfval,prunenodenummat,prunenodenummattest)
	IMPLICIT NONE
	integer,intent(in) :: prunind,testdatasize,maxdepth,traindatasize
	integer,intent(in) :: nodenummattest(testdatasize,maxdepth),nodenummat(traindatasize,maxdepth)
	real(8),intent(in) :: allfval((2**maxdepth)-1)
	real(8),intent(in) :: gamma
	integer,intent(out) :: prunenodenummat(traindatasize,maxdepth),prunenodenummattest(testdatasize,maxdepth)
	real(8) gammavec((2**(maxdepth-1))-1),allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	real(8) minghval
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:),nodenummatnewtest(:,:),nodenummatnewsubtest(:,:)
	if(prunind==1) then
		prunenodenummattest(:,:) = nodenummattest(:,:)
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	gammavec(:) = 0d0
	call cvgterminalnodecount(nodenummat,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call cvgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	gammavec(1) = minghval
	if(gammavec(1) > gamma) then
		prunenodenummattest(:,:) = nodenummattest(:,:)
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	allocate(nodenummatnew(traindatasize,maxdepth),nodenummatnewsub(traindatasize,maxdepth))
	allocate(nodenummatnewtest(testdatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
	call cvgpruntreemat(nodenummat,maxdepth,traindatasize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	call cvgpruntreemattest(nodenummattest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
	deallocate(nodenummatnewsub,nodenummatnewsubtest)
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call cvgterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			prunenodenummattest(:,:) = 0d0
			prunenodenummattest(:,1) = 1d0
			prunenodenummat(:,:) = 0d0
			prunenodenummat(:,1) = 1d0
			exit
		endif
		call cvgweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		gammavec(prunloop) = minghval
		if(gammavec(prunloop-1) < gamma .and. gammavec(prunloop) > gamma) then
			prunenodenummattest(:,:) = nodenummatnewtest(:,:)
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
		allocate(nodenummatnewsub(traindatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
		call cvgpruntreemat(nodenummatnew,maxdepth,traindatasize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		call cvgpruntreemattest(nodenummatnewtest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub,nodenummatnewsubtest)
	enddo
5000 continue
end subroutine cvgammatreepruning
subroutine cvgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine cvgterminalnodecount
subroutine cvgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	real(8) allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	real(8), intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine cvgweaknode
subroutine cvgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	real(8), intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	real(8), intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine cvgpruntreemat
subroutine cvgpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine cvgpruntreemattest
subroutine cvbesttreepruning(traindatasize,testdatasize,maxdepth,nodenummat,nodenummattest,allfval,&
levelcount,colnum,traindata,testdata,allgammaval,gammacv,gammar2cv)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,levelcount,traindatasize,colnum,testdatasize
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	real(8), intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	real(8), intent(in) :: allfval((2**maxdepth)-1),allgammaval((2**(maxdepth-1))-1)
	real(8), intent(out) :: gammacv((2**(maxdepth-1))-1),gammar2cv((2**(maxdepth-1))-1)
	real(8) allgammavaltrain((2**(maxdepth-1))-1),losspredsumvec((2**(maxdepth-1))-1)
	real(8) allfvalnew((2**maxdepth)-1),r2cvvec((2**(maxdepth-1))-1)
	real(8) losspredsum,minghval,r2cvval
	integer cvprunloop,minghnum,allnodenum,nottnodeval,i,j,k
	integer nottnodevec((2**maxdepth)-1),ncountval((2**maxdepth)-1)
	integer :: nodenummatnew(traindatasize,maxdepth),nodenummatnewtest(testdatasize,maxdepth)
	integer :: indcol
	allgammavaltrain(:) = 0d0
	gammacv(:) = 0d0
	losspredsumvec(:) = 0d0
	gammar2cv(:) = 0d0
	r2cvvec(:) = 0d0
	call cvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
	nodenummattest,testdatasize,maxdepth,losspredsum)
	losspredsumvec(1) = losspredsum
	call R2CV(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
	nodenummattest,testdatasize,maxdepth,r2cvval)
	r2cvvec(1) = r2cvval
	allfvalnew(:) = allfval(:)
	nodenummatnew(:,:) = nodenummat(:,:)
	nodenummatnewtest(:,:) = nodenummattest(:,:)
	do cvprunloop = 1,((2**(maxdepth-1))-2)
		call cvbestterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call cvbestweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allfvalnew(minghnum) = 0d0
		do i = 1,(maxdepth-1)
			if(minghnum < (2**i)) then
				indcol = i
				exit
			endif
		enddo
		do i = 1,traindatasize
			if(nodenummatnew(i,indcol) == minghnum) then
				do j = (indcol+1),maxdepth
					if(nodenummatnew(i,j) > 0) then
						allfvalnew(nodenummatnew(i,j)) = 0d0
					endif
					nodenummatnew(i,j) = 0
				enddo
			endif
		enddo
		do i = 1,testdatasize
			if(nodenummatnewtest(i,indcol) == minghnum) then
				do j = (indcol+1),maxdepth
					nodenummatnewtest(i,j) = 0
				enddo
			endif
		enddo
		allgammavaltrain(cvprunloop+1) = minghval
		call cvlosspredict(traindata,traindatasize,nodenummatnew,testdata,colnum,levelcount,&
		nodenummatnewtest,testdatasize,maxdepth,losspredsum)
		losspredsumvec(cvprunloop+1) = losspredsum
		call R2CV(traindata,traindatasize,nodenummatnew,testdata,colnum,levelcount,&
		nodenummatnewtest,testdatasize,maxdepth,r2cvval)
		r2cvvec(cvprunloop+1) = r2cvval
	enddo
	gammacv(1) = losspredsumvec(1)
	gammar2cv(1) = r2cvvec(1)
	j = 2
	do i = 2,size(allgammaval)
		if(allgammaval(i) == 0d0) then
			exit
		endif
		if(allgammaval(i) <= allgammavaltrain(j)) then
			gammacv(i) = losspredsumvec(j-1)
			gammar2cv(i) = r2cvvec(j-1)
		else
			do k = 1,size(allgammaval)
				if(allgammaval(i) > allgammavaltrain(j+k) .and. allgammavaltrain(j+k) > 0d0) then
					j = j + 1
				else
					exit
				endif
			enddo
			gammacv(i) = losspredsumvec(j)
			gammar2cv(i) = r2cvvec(j)
			j = j + 1
		endif
	enddo
end subroutine cvbesttreepruning
subroutine cvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
nodenummattest,testdatasize,maxdepth,losspredsum)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,levelcount
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	real(8), intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	real(8), intent(out) :: losspredsum
	real(8), allocatable :: timepred(:,:),losspred(:,:), timepredcou(:,:)
	integer i,j,k,l,maxactive_depth,nidx,tidx
	allocate(timepred(((2**maxdepth)-1),levelcount),losspred(((2**maxdepth)-1),levelcount))
	allocate(timepredcou(((2**maxdepth)-1),levelcount))
	timepred(:,:) = 0d0
	losspred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	maxactive_depth = 0
	do i = 1,maxdepth
		if(sum(nodenummat(:,i)) == 0) exit
		maxactive_depth = i
	enddo
	do j = 1,traindatasize
		tidx = int(traindata(j,3))
		do i = maxactive_depth, 1, -1
			nidx = nodenummat(j,i)
			if(nidx > 0) then
				if(i == maxactive_depth .or. nodenummat(j,i+1) == 0) then
					timepred(nidx,tidx) = timepred(nidx,tidx) + traindata(j,1)
					timepredcou(nidx,tidx) = timepredcou(nidx,tidx) + 1d0
				endif
				exit
			endif
		enddo
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j=1,maxdepth
				if(2**(j-1) <= i .and. i < 2**j) then
					k = j
					exit
				endif
			enddo
			do l = 1,testdatasize
				if(nodenummattest(l,k) == i) then
					losspred(i,int(testdata(l,3))) = losspred(i,int(testdata(l,3))) + ((testdata(l,1) - timepred(i,int(testdata(l,3))))**2)
				endif
			enddo
		endif
	enddo
	losspredsum = sum(losspred)
	deallocate(timepred,losspred,timepredcou)
end subroutine cvlosspredict
subroutine cvbestterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine cvbestterminalnodecount
subroutine cvbestweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	real(8) allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	real(8), intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine cvbestweaknode
subroutine cvbestpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	real(8), intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	real(8), intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine cvbestpruntreemat
subroutine cvbestpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine cvbestpruntreemattest
subroutine gammatreepruning(prunind,msize,bestgammaval,cv,maxdepth,nodenummat,allfval,prunenodenummat)
	implicit none
	integer,intent(in) :: msize,maxdepth,prunind,cv
	integer,intent(in) :: nodenummat(msize,maxdepth)
	double precision,intent(in) :: bestgammaval,allfval((2**maxdepth)-1)
	integer,intent(out) :: prunenodenummat(msize,maxdepth)
	double precision minghval
	double precision gammavec((2**(maxdepth-1))-1),allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:)
	if(bestgammaval <= 0d0 .or. prunind==1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	gammavec(:) = 0d0
	call gterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call gweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	gammavec(1) = minghval
	if(gammavec(1) > bestgammaval .and. cv == -1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	allocate(nodenummatnew(msize,maxdepth),nodenummatnewsub(msize,maxdepth))
	call gpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	deallocate(nodenummatnewsub)
	if(bestgammaval == minghval .and. cv == 1) then
		prunenodenummat(:,:) = nodenummatnew(:,:)
		goto 5000
	endif
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call gterminalnodecount(nodenummatnew,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			prunenodenummat(:,:) = 0d0
			prunenodenummat(:,1) = 1d0
			exit
		endif
		call gweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		gammavec(prunloop) = minghval
		if(gammavec(prunloop-1) < bestgammaval .and. gammavec(prunloop) > bestgammaval .and. cv == -1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
		allocate(nodenummatnewsub(msize,maxdepth))
		call gpruntreemat(nodenummatnew,maxdepth,msize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub)
		if(bestgammaval == minghval .and. cv == 1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
	enddo
5000 continue
end subroutine gammatreepruning
subroutine gterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine gterminalnodecount
subroutine gweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine gweaknode
subroutine gpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine gpruntreemat
subroutine treepredict(msize,levelcount,maxdepth,colnum,prunenodenummat,XYDATA,predvec,datatnnodenum)
	implicit none
	integer, intent(in) :: msize,levelcount,maxdepth,colnum
	integer, intent(in) :: prunenodenummat(msize,maxdepth)
	double precision, intent(in) :: XYDATA(Msize,colnum)
	integer, intent(out) :: datatnnodenum(msize)
	double precision, intent(out) :: predvec(msize)
	double precision, allocatable :: timepredsum(:,:),timepredcou(:,:)
	double precision tnodepredmat((2**maxdepth)-1,levelcount)
	integer i,j,maxactive_depth,nidx,tidx
	allocate(timepredsum(((2**maxdepth)-1),levelcount),timepredcou(((2**maxdepth)-1),levelcount))
	timepredsum(:,:) = 0d0
	timepredcou(:,:) = 0d0
	datatnnodenum(:) = 0
	maxactive_depth = 0
	do i = 1,maxdepth
		if(sum(prunenodenummat(:,i)) == 0) exit
		maxactive_depth = i
	enddo
	do j = 1,msize
		tidx = int(XYDATA(j,3))
		do i = maxactive_depth, 1, -1
			nidx = prunenodenummat(j,i)
			if(nidx > 0) then
				if(i == maxactive_depth .or. prunenodenummat(j,i+1) == 0) then
					timepredsum(nidx,tidx) = timepredsum(nidx,tidx) + XYDATA(j,1)
					timepredcou(nidx,tidx) = timepredcou(nidx,tidx) + 1d0
					datatnnodenum(j) = nidx
				endif
				exit
			endif
		enddo
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepredsum(i,:))) > 0d0) then
			do j = 1,levelcount
				tnodepredmat(i,j) = timepredsum(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,msize
		predvec(i) = tnodepredmat(datatnnodenum(i),int(xydata(i,3)))
	enddo
end subroutine treepredict
subroutine nodedata(xydata,msize,colnum,nodenum,hierarchy,maxdepth,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize,maxdepth
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine nodedata
subroutine splitvec(nodedata,nodedatasize,colnum,msize,maxdepth,DATATYPE,prunnodenummat,&
ind1,ind2,splitvecsize,splitnumber,splitvector)
	IMPLICIT NONE
	integer, intent(in) :: nodedatasize,colnum,maxdepth,ind1,ind2,splitvecsize,msize
	integer, intent(in) :: datatype(colnum-3)
	double precision, intent(in) :: nodedata(nodedatasize,colnum)
	integer, intent(in) :: prunnodenummat(msize,maxdepth)
	integer, intent(out) :: splitvector(splitvecsize)
	double precision, intent(out) :: splitnumber(splitvecsize)
	integer i,j,hierarchy,nodesize,facsum,count_0,count_1,idx,splitnum,countvec
	double precision datasample(nodedatasize)
	integer, allocatable :: splitindmat(:,:)
	datasample = nodedata(:,ind1)
	if(datatype(ind1-3) == 1) then
		splitnum = splitvecsize - 1
	elseif(datatype(ind1-3) == 2) then
		splitnum = (2 ** (splitvecsize-1)) - 1
	endif
	call spdataval(nodedata(:,ind1),nodedatasize,splitnumber,splitvecsize)
	allocate(splitindmat(splitnum,splitvecsize))
	if(datatype(ind1-3) == 1) then
		do i = 1,splitnum
			do j = 1,splitvecsize
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype(ind1-3) == 2) then
	    idx = 1
		do i = 0, 2**(splitvecsize-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, splitvecsize - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
	splitvector = splitindmat(ind2,:)
end subroutine splitvec
subroutine spdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call spdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine spdataval
subroutine spdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call spdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine spdatasum
recursive subroutine spdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call spdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call spdatasort(datavec, j+1, msize)
	endif
	return
end subroutine spdatasort
subroutine threetreesbootstrap(msize, bootsize, colnum, xydata, levelcount, bootdata, oridata)
	IMPLICIT NONE
	integer, intent(in) :: msize,bootsize,colnum,levelcount
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: oridata(bootsize*levelcount)
	double precision, intent(out) :: bootdata(bootsize*levelcount,colnum)
	integer idsum,randval,i,j,k,l,m
	integer oriind(msize)
	double precision randvalsub
	double precision idnum(levelcount)
	call random_seed()
	do i = 1,msize
		oriind(i) = i
	enddo
	call threetreesbsdatasum(xydata(:,2),msize,idsum)
	j = 1
	k = levelcount
	do i=1,bootsize
		call random_number(randvalsub)
		randval = int(randvalsub * dble(idsum)) + 1
		l = (randval-1)*levelcount+1
		m = randval*levelcount
		idnum(:) = dble(i)
		oridata(j:k)=oriind(l:m)
		bootdata(j:k,1) = xydata(l:m,1)
		bootdata(j:k,2) = idnum(:)
		bootdata(j:k,3:colnum) = xydata(l:m,3:colnum)
		j = j + levelcount
		k = k + levelcount
	enddo
end subroutine threetreesbootstrap
subroutine threetreesbsdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesbsdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesbsdatasum
recursive subroutine threetreesbsdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesbsdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesbsdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesbsdatasort
subroutine threetreesboottreegrowth(nodenummatboot,nodenummatori,allfval,prunind,bootdatasize,colnum,bootdata,datatype,fixweight,&
beta1,beta2,beta1len,beta2len,levelcount,minbucket,oridata,oridatasize,alpha,maxdepth,minsplit)
	IMPLICIT NONE
	integer, intent(in) :: bootdatasize,oridatasize,maxdepth,colnum,beta1len,beta2len,levelcount,minsplit,minbucket
	integer, intent(in) :: datatype(colnum-3)
	double precision, intent(in) :: fixweight,alpha
	double precision, intent(in) :: bootdata(bootdatasize,colnum),beta1(beta1len),beta2(beta2len)
	double precision, intent(in) :: oridata(oridatasize,colnum)
	integer,intent(out) :: prunind
	integer, intent(out) :: nodenummatboot(bootdatasize,maxdepth),nodenummatori(oridatasize,maxdepth)
	double precision,intent(out) :: allfval((2**maxdepth)-1)
	integer nodenummatsub(bootdatasize,maxdepth),nodenummatsubori(oridatasize,maxdepth)
	integer nodenum,hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,separatecou,separateint,sizenum
	integer sizel,sizer,sizelori,sizerori,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5)
	double precision splitmcp,splitpval,weightval,weight,weightpval,splitweight,splitwfval,separatesp,alphamcp
	double precision fval(2),splitfval(2),splitmcppval(2)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:),splitindvec(:),nodesizeori(:)
	integer,allocatable :: nodesizesub(:),nodesizesubori(:)
	double precision, allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),separateval(:)
	double precision, allocatable :: xynodedata(:,:),xynodedataori(:,:)
	double precision, allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer, allocatable :: flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	double precision :: splitgroupsum
	logical :: dfvec_set
	nodenummatboot(:,:) = 0
	nodenummatboot(:,1) = 1
	nodenummatori(:,:) = 0
	nodenummatori(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2),nodesizeori(2))
	prunind=0
	splitpval = 1d0
	call threetreesbootsplitcount(bootdatasize, colnum-3, bootdata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(bootdatasize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		call threetreesbootsplitmat(ind1,datatype(ind1-3),bootdata,bootdatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		do ind2 = 1,splitnum(ind1-3)
			indcou = indcou + 1
			indmat(indcou,1) = ind1
			indmat(indcou,2) = ind2
			call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),bootdata,bootdatasize,colnum,ind1,anovadata,facvalout)
			call threetreesbootrepANOVA(bootdatasize,colnum,anovadata,fval,dfvec)
			fval_cache(indcou,1) = fval(1)
			fval_cache(indcou,2) = fval(2)
			groupsum_cache(indcou) = sum(anovadata(:,4))
			if (.not. dfvec_set) then
				dfvec_const = dfvec
				dfvec_set = .true.
			endif
			if(fixweight == -1.0d0) then
				do wcou = 0,10
					weightval = 0.1d0 * dble(wcou)
					wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				enddo
			else
				weightval = fixweight
				wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
			endif
		enddo
		deallocate(splitindmat,facvalout)
	enddo
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call threetreesbootweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(bootdatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = indmat(flat_idx,1)
				splitind2 = indmat(flat_idx,2)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesbootsplitmat(ind1,datatype(ind1-3),bootdata,bootdatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			bootdata,bootdatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesbootdatasum(oridata(:,splitind1),oridatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesbootdataval(oridata(:,splitind1),oridatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call threetreesbootweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(bootdatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = indmat(flat_idx,1)
			splitind2 = indmat(flat_idx,2)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
		endif
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesbootsplitmat(ind1,datatype(ind1-3),bootdata,bootdatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			bootdata,bootdatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesbootdatasum(oridata(:,splitind1),oridatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesbootdataval(oridata(:,splitind1),oridatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	endif
	if (splitpval >= 1d0) then
		prunind = 1
		goto 2002
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call threetreesbootweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call threetreesbootweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum < dble(levelcount*minbucket) .or. &
	(dble(bootdatasize) - splitgroupsum) < dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	sizenum = size(splitfacval)
	call threetreesbootnodenumber(bootdata,maxdepth,bootdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummatboot,nodenummatsub,sizel,sizer)
	call threetreesbootnodenumber(oridata,maxdepth,oridatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummatori,nodenummatsubori,sizelori,sizerori)
	nodesize(1) = sizel
	nodesize(2) = sizer
	nodesizeori(1) = sizelori
	nodesizeori(2) = sizerori
	deallocate(anovadata)
	allfval(1) = splitwfval
	nodenummatboot(:,:) = nodenummatsub(:,:)
	nodenummatori(:,:) = nodenummatsubori(:,:)
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4),xynodedataori(nodesizeori(nodeloop),colnum))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call threetreesbootnodedata(bootdata,bootdatasize,colnum,nodenum,hierarchy,nodenummatboot,nodesize(nodeloop),xynodedata)
			call threetreesbootnodedata(oridata,oridatasize,colnum,nodenum,hierarchy,nodenummatori,nodesizeori(nodeloop),xynodedataori)
			call threetreesbootsplitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			indcou = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) then
					deallocate(splitindmat)
				endif
				if(.not. allocated(splitindmat)) then
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				endif
				if(allocated(facvalout)) then
					deallocate(facvalout)
				endif
				if(.not. allocated(facvalout)) then
					allocate(facvalout(countvec(ind1-3)))
				endif
				call threetreesbootsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),&
				countvec(ind1-3),splitindmat)
				do ind2 = 1,splitnum(ind1-3)
					indcou = indcou + 1
					indmat(indcou,1) = ind1
					indmat(indcou,2) = ind2
					call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),&
					colnum,ind1,anovadata,facvalout)
					call threetreesbootrepANOVA(nodesize(nodeloop),colnum,anovadata,fval,dfvec)
					fval_cache(indcou,1) = fval(1)
					fval_cache(indcou,2) = fval(2)
					groupsum_cache(indcou) = sum(anovadata(:,4))
					if (.not. dfvec_set) then
						dfvec_const = dfvec
						dfvec_set = .true.
					endif
					if(fixweight == -1.0d0) then
						do wcou = 0,10
							weightval = 0.1d0 * dble(wcou)
							wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						enddo
					else
						weightval = fixweight
						wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					endif
				enddo
				deallocate(splitindmat,facvalout)
2000			continue
			enddo
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call threetreesbootweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = indmat(flat_idx,1)
						splitind2 = indmat(flat_idx,2)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesbootsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesbootdatasum(oridata(:,splitind1),oridatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesbootdataval(oridata(:,splitind1),oridatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call threetreesbootweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = indmat(flat_idx,1)
					splitind2 = indmat(flat_idx,2)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
				endif
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesbootsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesbootsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesbootdatasum(oridata(:,splitind1),oridatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesbootdataval(oridata(:,splitind1),oridatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			endif
			if (splitpval >= 1d0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call threetreesbootweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call threetreesbootweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum < dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) < dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			if(.not. allocated(nodesizesubori)) then
				allocate(nodesizesubori(2**hierarchy))
				nodesizesubori(:) = 0
			endif
			sizenum = size(splitfacval)
			call threetreesbootnodenumber(bootdata,maxdepth,bootdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummatboot,nodenummatsub,sizel,sizer)
			call threetreesbootnodenumber(oridata,maxdepth,oridatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummatori,nodenummatsubori,sizelori,sizerori)
			nodenummatboot(:,:) = nodenummatsub(:,:)
			nodenummatori(:,:) = nodenummatsubori(:,:)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			nodesizesubori(2*nodeloop-1) = sizelori
			nodesizesubori(2*nodeloop) = sizerori
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			deallocate(anovadata,xynodedata,xynodedataori)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize,nodesizeori)
		allocate(nodesize(2**hierarchy),nodesizeori(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		nodesizeori(:) = nodesizesubori(:)
		deallocate(nodesizesub,nodesizesubori)
	enddo
2003 continue
	deallocate(nodesize,nodesizeori)
2002 continue
end subroutine threetreesboottreegrowth
subroutine threetreesbootsplitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	double precision, intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	double precision datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call threetreesbootdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call threetreesbootdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine threetreesbootsplitcount
subroutine threetreesbootdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesbootdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesbootdatasum
recursive subroutine threetreesbootdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesbootdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesbootdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesbootdatasort
subroutine threetreesbootsplitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
end subroutine threetreesbootsplitmat
subroutine threetreesbootsplitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	double precision, intent(in) :: xydata(msize,colnum)
	double precision, intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	double precision facval(countvec)
	call threetreesbootdataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
			endif
		enddo
	enddo
end subroutine threetreesbootsplitdata
subroutine threetreesbootrepANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	double precision, intent(in) :: anovadata(msize,4)
	double precision, intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	double precision ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	double precision ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	double precision, allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	double precision, allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine threetreesbootrepANOVA
subroutine threetreesbootweightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	double precision, intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: weightpval
	double precision DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	double precision xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call threetreesbootpfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call threetreesbootpfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call threetreesbootdemethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE threetreesbootweightedpval
subroutine threetreesbootpfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	double precision,parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	double precision,intent(in)::a,b,eps,df1,df2,beta
	double precision,intent(out)::s
	double precision res,zval
	double precision inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine threetreesbootpfdist
subroutine threetreesbootdemethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	double precision,intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    double precision,intent(out)::s
	integer,parameter::kmin=3, kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    double precision yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call threetreesbootdemethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call threetreesbootdemethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesbootdemethod
subroutine threetreesbootdemethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    double precision,intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    double precision,intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    double precision inv_weight
    double precision const_factor, df_ratio1, df_ratio2
    double precision df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    double precision v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesbootdemethod2
subroutine threetreesbootweightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	double precision,intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	double precision,intent(out) :: res
	double precision zval,form1,form2,form3,form4,form5,form6,form7,form8,form9,s1,s2,eps
	eps=1d-12
	s1 = 0d0
	s2 = 0d0
	zval = (z-((1d0-weight)*v))/weight
	form1 = 1d0 / weight
	form2 = 1d0 / beta1
	form3 = (df11/df12)**(df11/2d0)
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+((df11/df12)*zval))**((df11+df12)/2d0)
	form6 = 1d0 / beta2
	form7 = (df21/df22)**(df21/2d0)
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+((df21/df22)*v))**((df21+df22)/2d0)
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine threetreesbootweightfformula
subroutine threetreesbootdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreesbootdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreesbootdataval
subroutine threetreesbootnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,nodenummatsub,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	double precision, intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer,nodenummatsub(msize,maxdepth)
	integer i,j
	sizel=0
	sizer=0
	nodenummatsub(:,:) = nodenummat(:,:)
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummatsub(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummatsub(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine threetreesbootnodenumber
subroutine threetreesbootnodedata(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,11)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine threetreesbootnodedata
subroutine threetreesbootcvtreepruning(prunind,msize,alpha,gamma,cv,maxdepth,nodenummat,allfval,allgammaval)
	IMPLICIT NONE
	integer,intent(in) :: prunind,msize,cv,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	double precision,intent(in) :: alpha,gamma,allfval((2**maxdepth)-1)
	double precision,intent(out) :: allgammaval((2**(maxdepth-1))-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision minghval,allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:)
	allgammaval(:) = 0d0
	if(prunind == 1 .or. alpha < 1d0 .or. gamma >= 0d0 .or. cv == -1) then
		goto 3001
	endif
	call threetreesbootcvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call threetreesbootcvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	allocate(nodenummatnew(msize,maxdepth),nodenummatnewsub(msize,maxdepth))
	call threetreesbootcvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	deallocate(nodenummatnewsub)
	allgammaval(2) = minghval
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesbootcvterminalnodecount(nodenummatnew,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call threetreesbootcvweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allocate(nodenummatnewsub(msize,maxdepth))
		call threetreesbootcvpruntreemat(nodenummatnew,maxdepth,msize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub)
		allgammaval(prunloop+1) = minghval
	enddo
3001 continue
end subroutine threetreesbootcvtreepruning
subroutine threetreesbootcvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesbootcvterminalnodecount
subroutine threetreesbootcvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	double precision testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesbootcvweaknode
subroutine threetreesbootcvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootcvpruntreemat
subroutine threetreesbootcrossvaridation(gamma,alpha,cv,xydata,msize,colnum,Ksplit,levelcount,maxdepth,beta1,beta2,&
beta1len,beta2len,minbucket,minsplit,fixweight,datatype,allgammaval,bestgammaval,cvsplitind,iseed)
	IMPLICIT NONE
	integer,intent(in) :: cv,msize,colnum,Ksplit,maxdepth,levelcount,beta1len,beta2len,minbucket,minsplit
	integer,intent(in) :: datatype(colnum-3)
	integer,intent(in) :: iseed
	double precision,intent(in) :: alpha,gamma,fixweight
	double precision,intent(in) :: beta1(beta1len),beta2(beta2len),allgammaval((2**(maxdepth-1))-1)
	double precision,intent(in) :: xydata(msize,colnum)
	double precision,intent(out) :: bestgammaval
	integer,intent(out) :: cvsplitind(msize)
	integer, allocatable :: cvind(:),cvsize(:)
	integer, allocatable ::  nodenummat(:,:), nodenummattest(:,:),prunenodenummattest(:,:)
	double precision, allocatable :: meangammacv(:)
	double precision, allocatable :: gammacvmat(:,:),traindata(:,:),testdata(:,:)
	integer cvloop,traindatasize,testdatasize,prunind,i
	double precision allfval((2**maxdepth)-1),gammacv((2**(maxdepth-1))-1)
	double precision maxgammasub
	if(alpha < 1d0 .or. gamma >= 0d0 .or. cv == -1) then
		bestgammaval = gamma
		allocate(cvind(msize))
		cvind(:) = 0
		cvsplitind(:) = cvind(:)
		goto 7001
	endif
	allocate(cvind(msize),cvsize(Ksplit),gammacvmat(ksplit,(2**(maxdepth-1))-1))
	allocate(meangammacv((2**(maxdepth-1))-1))
	call threetreesbootcvdata(XYDATA,msize,colnum,Ksplit,levelcount,cvind,cvsize,iseed)
	cvsplitind(:) = cvind(:)
	do cvloop = 1,Ksplit
		traindatasize = ((sum(cvsize)-cvsize(cvloop))*levelcount)
		testdatasize = (cvsize(cvloop)*levelcount)
		allocate(traindata(traindatasize,colnum),testdata(testdatasize,colnum))
		allocate(nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth))
		call threetreesbootcvdatachoice(XYDATA,msize,colnum,Ksplit,levelcount,cvloop,cvind,cvsize,traindata,testdata)
		call threetreesbootcvtreegrowth(traindatasize,testdatasize,traindata,testdata,nodenummattest,fixweight,&
		maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,datatype,beta1,beta2,beta1len,&
		beta2len,nodenummat,allfval,prunind)
		if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
			call threetreesbootcvbesttreepruning(traindatasize,testdatasize,maxdepth,nodenummat,nodenummattest,allfval,&
			levelcount,colnum,traindata,testdata,allgammaval,gammacv)
			gammacvmat(cvloop,:) = gammacv(:)
		endif
		deallocate(traindata,testdata,nodenummat,nodenummattest)
	enddo
	if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
		do i = 1,size(allgammaval)
			meangammacv(i) = sum(gammacvmat(:,i))
			if(meangammacv(i) > 0) then
				meangammacv(i) = meangammacv(i) / dble(msize)
			else
				meangammacv(i) = -1d0
			endif
		enddo
		maxgammasub = maxval(meangammacv) + 1d0
		do i = 1,size(meangammacv)
			if(meangammacv(i) < maxgammasub .and. meangammacv(i) >= 0d0) then
				bestgammaval = allgammaval(i)
				maxgammasub = meangammacv(i)
			endif
		enddo
	endif
7001 continue
end subroutine threetreesbootcrossvaridation
subroutine threetreesbootcvdata(XYDATA,msize,colnum,Ksplit,levelcount,cvind,cvsize,iseed)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,levelcount
	integer, intent(in) :: iseed
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: cvind(msize), cvsize(Ksplit)
	integer i,subnum, randval, cvsizecou(Ksplit)
	integer, allocatable :: cvindsub(:)
	double precision randvalsub,ii
	integer :: seed_size, seed_i
	integer, allocatable :: seed_array(:)
	call random_seed(size=seed_size)
	allocate(seed_array(seed_size))
	do seed_i = 1, seed_size
		seed_array(seed_i) = iseed + (seed_i - 1) * 37
	enddo
	call random_seed(put=seed_array)
	deallocate(seed_array)
	subnum = msize/levelcount
	cvsize(:) = subnum/Ksplit
	do i = 1,(subnum - sum(cvsize))
		cvsize(i) = cvsize(i) + 1
	enddo
	allocate(cvindsub(subnum))
	cvsizecou(:) = cvsize(:)
	do i = 1,subnum
		do
		    call random_number(randvalsub)
			randval = int(randvalsub * dble(Ksplit)) + 1
			if(cvsizecou(randval) > 0)then
				cvsizecou(randval) = cvsizecou(randval) - 1
				cvindsub(i) = randval
				exit
			endif
		enddo
	enddo
	do i = 1,subnum
		cvind((levelcount*(i-1)+1):(levelcount*i)) = cvindsub(i)
	enddo
end subroutine threetreesbootcvdata
subroutine threetreesbootcvdatachoice(XYDATA,msize,colnum,Ksplit,levelcount,testind,cvind,cvsize,traindata,testdata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,testind,levelcount
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: cvind(msize),cvsize(Ksplit)
	double precision, intent(out) :: traindata(((sum(cvsize)-cvsize(testind))*levelcount),colnum),&
	testdata((cvsize(testind)*levelcount),colnum)
	integer i,jtrain,jtest,subnum
	subnum = msize/levelcount
	jtest = 1
	jtrain = 1
	do i = 1,subnum
		if(cvind(((i-1)*levelcount)+1) == testind) then
			testdata((levelcount*(jtest-1)+1):(levelcount*jtest),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtest = jtest + 1
		else
			traindata((levelcount*(jtrain-1)+1):(levelcount*jtrain),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtrain = jtrain + 1
		endif
	enddo
end subroutine threetreesbootcvdatachoice
subroutine threetreesbootcvtreegrowth(traindatasize,testdatasize,traindata,testdata,nodenummattest,fixweight,&
maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,datatype,beta1,beta2,beta1len,&
beta2len,nodenummat,allfval,prunind)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,beta1len,beta2len,levelcount,minsplit,minbucket,msize
	integer, intent(in) :: datatype(colnum-3)
	double precision, intent(in) :: fixweight,alpha
	double precision, intent(in) :: traindata(traindatasize,colnum),beta1(beta1len),beta2(beta2len)
	double precision, intent(in) :: xydata(msize,colnum),testdata(testdatasize,colnum)
	integer, intent(out) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	integer,intent(out) :: prunind
	double precision,intent(out) :: allfval((2**maxdepth)-1)
	integer nodenummatsub(traindatasize,maxdepth),nodenummatsubtest(testdatasize,maxdepth)
	integer nodenum,hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,separatecou,separateint,sizenum
	integer sizel,sizer,sizeltest,sizertest,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5)
	double precision splitmcp,splitpval,weightval,weight,weightpval,splitweight,splitwfval,separatesp,alphamcp
	double precision fval(2),splitfval(2),splitmcppval(2)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:),splitindvec(:),nodesizetest(:)
	integer,allocatable :: nodesizesub(:),nodesizesubtest(:)
	double precision, allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),separateval(:)
	double precision, allocatable :: xynodedata(:,:),xynodedatatest(:,:)
	double precision, allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer, allocatable :: flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	double precision :: splitgroupsum
	logical :: dfvec_set
	nodenummat(:,:) = 0
	nodenummat(:,1) = 1
	nodenummattest(:,:) = 0
	nodenummattest(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2),nodesizetest(2))
	prunind=0
	splitpval = 1d0
	call threetreesbootcvsplitcount(traindatasize, colnum-3, traindata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(traindatasize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		call threetreesbootcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		do ind2 = 1,splitnum(ind1-3)
			indcou = indcou + 1
			indmat(indcou,1) = ind1
			indmat(indcou,2) = ind2
			call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			call threetreesbootcvrepANOVA(traindatasize,colnum,anovadata,fval,dfvec)
			fval_cache(indcou,1) = fval(1)
			fval_cache(indcou,2) = fval(2)
			groupsum_cache(indcou) = sum(anovadata(:,4))
			if (.not. dfvec_set) then
				dfvec_const = dfvec
				dfvec_set = .true.
			endif
			if(fixweight == -1.0d0) then
				do wcou = 0,10
					weightval = 0.1d0 * dble(wcou)
					wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				enddo
			else
				weightval = fixweight
				wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
			endif
		enddo
		deallocate(splitindmat,facvalout)
	enddo
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call threetreesbootcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = indmat(flat_idx,1)
				splitind2 = indmat(flat_idx,2)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesbootcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesbootcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesbootcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call threetreesbootcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = indmat(flat_idx,1)
			splitind2 = indmat(flat_idx,2)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
		endif
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesbootcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesbootcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesbootcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	endif
	if (splitpval >= 1d0) then
		prunind = 1
		goto 2002
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call threetreesbootcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call threetreesbootcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum < dble(levelcount*minbucket) .or. &
	(dble(traindatasize) - splitgroupsum) < dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	sizenum = size(splitfacval)
	call threetreesbootcvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
	call threetreesbootcvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummattest,nodenummatsubtest,sizeltest,sizertest)
	nodesize(1) = sizel
	nodesize(2) = sizer
	nodesizetest(1) = sizeltest
	nodesizetest(2) = sizertest
	deallocate(anovadata)
	allfval(1) = splitwfval
	nodenummat(:,:) = nodenummatsub(:,:)
	nodenummattest(:,:) = nodenummatsubtest(:,:)
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4),xynodedatatest(nodesizetest(nodeloop),colnum))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call threetreesbootcvnodedata(traindata,traindatasize,colnum,nodenum,hierarchy,nodenummat,nodesize(nodeloop),xynodedata)
			call threetreesbootcvnodedata(testdata,testdatasize,colnum,nodenum,hierarchy,nodenummattest,&
			nodesizetest(nodeloop),xynodedatatest)
			call threetreesbootcvsplitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			indcou = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) then
					deallocate(splitindmat)
				endif
				if(.not. allocated(splitindmat)) then
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				endif
				if(allocated(facvalout)) then
					deallocate(facvalout)
				endif
				if(.not. allocated(facvalout)) then
					allocate(facvalout(countvec(ind1-3)))
				endif
				call threetreesbootcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
				splitnum(ind1-3),countvec(ind1-3),splitindmat)
				do ind2 = 1,splitnum(ind1-3)
					indcou = indcou + 1
					indmat(indcou,1) = ind1
					indmat(indcou,2) = ind2
					call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),&
					colnum,ind1,anovadata,facvalout)
					call threetreesbootcvrepANOVA(nodesize(nodeloop),colnum,anovadata,fval,dfvec)
					fval_cache(indcou,1) = fval(1)
					fval_cache(indcou,2) = fval(2)
					groupsum_cache(indcou) = sum(anovadata(:,4))
					if (.not. dfvec_set) then
						dfvec_const = dfvec
						dfvec_set = .true.
					endif
					if(fixweight == -1.0d0) then
						do wcou = 0,10
							weightval = 0.1d0 * dble(wcou)
							wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						enddo
					else
						weightval = fixweight
						wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					endif
				enddo
				deallocate(splitindmat,facvalout)
2000			continue
			enddo
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call threetreesbootcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = indmat(flat_idx,1)
						splitind2 = indmat(flat_idx,2)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesbootcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesbootcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesbootcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call threetreesbootcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = indmat(flat_idx,1)
					splitind2 = indmat(flat_idx,2)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
				endif
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesbootcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesbootcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesbootcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesbootcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			endif
			if (splitpval >= 1d0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call threetreesbootcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call threetreesbootcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum < dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) < dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			if(.not. allocated(nodesizesubtest)) then
				allocate(nodesizesubtest(2**hierarchy))
				nodesizesubtest(:) = 0
			endif
			sizenum = size(splitfacval)
			call threetreesbootcvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
			call threetreesbootcvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummattest,nodenummatsubtest,sizeltest,sizertest)
			nodenummat(:,:) = nodenummatsub(:,:)
			nodenummattest(:,:) = nodenummatsubtest(:,:)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			nodesizesubtest(2*nodeloop-1) = sizeltest
			nodesizesubtest(2*nodeloop) = sizertest
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			deallocate(anovadata,xynodedata,xynodedatatest)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize,nodesizetest)
		allocate(nodesize(2**hierarchy),nodesizetest(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		nodesizetest(:) = nodesizesubtest(:)
		deallocate(nodesizesub,nodesizesubtest)
	enddo
2003 continue
	deallocate(nodesize,nodesizetest)
2002 continue
end subroutine threetreesbootcvtreegrowth
subroutine threetreesbootcvsplitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	double precision, intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	double precision datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call threetreesbootcvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call threetreesbootcvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine threetreesbootcvsplitcount
subroutine threetreesbootcvdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesbootcvdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesbootcvdatasum
recursive subroutine threetreesbootcvdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesbootcvdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesbootcvdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesbootcvdatasort
subroutine threetreesbootcvsplitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
end subroutine threetreesbootcvsplitmat
subroutine threetreesbootcvsplitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	double precision, intent(in) :: xydata(msize,colnum)
	double precision, intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	double precision facval(countvec)
	call threetreesbootcvdataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
			endif
		enddo
	enddo
end subroutine threetreesbootcvsplitdata
subroutine threetreesbootcvrepANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	double precision, intent(in) :: anovadata(msize,4)
	double precision, intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	double precision ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	double precision ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	double precision, allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	double precision, allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine threetreesbootcvrepANOVA
subroutine threetreesbootcvweightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	double precision, intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: weightpval
	double precision DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	double precision xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call threetreesbootcvpfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call threetreesbootcvpfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call threetreesbootcvdemethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE threetreesbootcvweightedpval
subroutine threetreesbootcvpfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	double precision,parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	double precision,intent(in)::a,b,eps,df1,df2,beta
	double precision,intent(out)::s
	double precision res,zval
	double precision inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine threetreesbootcvpfdist
subroutine threetreesbootcvdemethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	double precision,intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    double precision,intent(out)::s
	integer,parameter::kmin=3, kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    double precision yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call threetreesbootcvdemethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call threetreesbootcvdemethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesbootcvdemethod
subroutine threetreesbootcvdemethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    double precision,intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    double precision,intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    double precision inv_weight
    double precision const_factor, df_ratio1, df_ratio2
    double precision df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    double precision v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesbootcvdemethod2
subroutine threetreesbootcvweightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	double precision,intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	double precision,intent(out) :: res
	double precision zval,form1,form2,form3,form4,form5,form6,form7,form8,form9,s1,s2,eps
	eps=1d-12
	s1 = 0d0
	s2 = 0d0
	zval = (z-((1d0-weight)*v))/weight
	form1 = 1d0 / weight
	form2 = 1d0 / beta1
	form3 = (df11/df12)**(df11/2d0)
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+((df11/df12)*zval))**((df11+df12)/2d0)
	form6 = 1d0 / beta2
	form7 = (df21/df22)**(df21/2d0)
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+((df21/df22)*v))**((df21+df22)/2d0)
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine threetreesbootcvweightfformula
subroutine threetreesbootcvdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreesbootcvdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreesbootcvdataval
subroutine threetreesbootcvnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,nodenummatsub,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	double precision, intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer,nodenummatsub(msize,maxdepth)
	integer i,j
	sizel=0
	sizer=0
	nodenummatsub(:,:) = nodenummat(:,:)
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummatsub(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummatsub(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine threetreesbootcvnodenumber
subroutine threetreesbootcvnodedata(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,11)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine threetreesbootcvnodedata
subroutine threetreesbootcvgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesbootcvgterminalnodecount
subroutine threetreesbootcvgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesbootcvgweaknode
subroutine threetreesbootcvgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootcvgpruntreemat
subroutine threetreesbootcvgpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootcvgpruntreemattest
subroutine threetreesbootcvbesttreepruning(traindatasize,testdatasize,maxdepth,nodenummat,nodenummattest,allfval,&
levelcount,colnum,traindata,testdata,allgammaval,gammacv)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,levelcount,traindatasize,colnum,testdatasize
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	double precision, intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	double precision, intent(in) :: allfval((2**maxdepth)-1),allgammaval((2**(maxdepth-1))-1)
	double precision, intent(out) :: gammacv((2**(maxdepth-1))-1)
	double precision allgammavaltrain((2**(maxdepth-1))-1),losspredsumvec((2**(maxdepth-1))-1)
	double precision allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	double precision losspredsum,minghval
	integer cvprunloop,minghnum,allnodenum,nottnodeval,i,j,k
	integer nottnodevec((2**maxdepth)-1),ncountval((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:),nodenummatnewtest(:,:),nodenummatnewsubtest(:,:)
	allgammavaltrain(:) = 0d0
	gammacv(:) = 0d0
	losspredsumvec(:) = 0d0
	call threetreesbootcvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
	nodenummattest,testdatasize,maxdepth,losspredsum)
	losspredsumvec(1) = losspredsum
	allocate(nodenummatnew(traindatasize,maxdepth),nodenummatnewtest(testdatasize,maxdepth))
	allfvalnew(:) = allfval(:)
	nodenummatnew(:,:) = nodenummat(:,:)
	nodenummatnewtest(:,:) = nodenummattest(:,:)
	do cvprunloop = 1,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesbootcvbestterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call threetreesbootcvbestweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allocate(nodenummatnewsub(traindatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
		call threetreesbootcvbestpruntreemat(nodenummatnew,maxdepth,traindatasize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		call threetreesbootcvbestpruntreemattest(nodenummatnewtest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub,nodenummatnewsubtest)
		allgammavaltrain(cvprunloop+1) = minghval
		call threetreesbootcvlosspredict(traindata,traindatasize,nodenummatnew,testdata,colnum,levelcount,&
		nodenummatnewtest,testdatasize,maxdepth,losspredsum)
		losspredsumvec(cvprunloop+1) = losspredsum
	enddo
	gammacv(1) = losspredsumvec(1)
	j = 2
	do i = 2,size(allgammaval)
		if(allgammaval(i) == 0d0) then
			exit
		endif
		if(allgammaval(i) <= allgammavaltrain(j)) then
			gammacv(i) = losspredsumvec(j-1)
		else
			do k = 1,size(allgammaval)
				if(allgammaval(i) > allgammavaltrain(j+k) .and. allgammavaltrain(j+k) > 0d0) then
					j = j + 1
				else
					exit
				endif
			enddo
			gammacv(i) = losspredsumvec(j)
			j = j + 1
		endif
	enddo
end subroutine threetreesbootcvbesttreepruning
subroutine threetreesbootcvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
nodenummattest,testdatasize,maxdepth,losspredsum)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,levelcount
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	double precision, intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	double precision, intent(out) :: losspredsum
	double precision, allocatable :: timepred(:,:),losspred(:,:), timepredcou(:,:)
	integer i,j,k,l
	allocate(timepred(((2**maxdepth)-1),levelcount),losspred(((2**maxdepth)-1),levelcount))
	allocate(timepredcou(((2**maxdepth)-1),levelcount))
	timepred(:,:) = 0d0
	losspred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize
			if(sum(nodenummat(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(nodenummat(j,maxdepth) > 0) then
					timepred(nodenummat(j,maxdepth),int(traindata(j,3))) = timepred(nodenummat(j,maxdepth),int(traindata(j,3))) + traindata(j,1)
					timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) = timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) + 1d0
				endif
			elseif(nodenummat(j,i) > 0 .and. nodenummat(j,i+1) == 0) then
				timepred(nodenummat(j,i),int(traindata(j,3))) = timepred(nodenummat(j,i),int(traindata(j,3))) + traindata(j,1)
				timepredcou(nodenummat(j,i),int(traindata(j,3))) = timepredcou(nodenummat(j,i),int(traindata(j,3))) + 1d0
			endif
		enddo
	enddo
3010 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j=1,maxdepth
				if(2**(j-1) <= i .and. i < 2**j) then
					k = j
					exit
				endif
			enddo
			do l = 1,testdatasize
				if(nodenummattest(l,k) == i) then
					losspred(i,int(testdata(l,3))) = losspred(i,int(testdata(l,3))) + ((testdata(l,1) - timepred(i,int(testdata(l,3))))**2)
				endif
			enddo
		endif
	enddo
	losspredsum = sum(losspred)
	deallocate(timepred,losspred,timepredcou)
end subroutine threetreesbootcvlosspredict
subroutine threetreesbootcvbestterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesbootcvbestterminalnodecount
subroutine threetreesbootcvbestweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesbootcvbestweaknode
subroutine threetreesbootcvbestpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootcvbestpruntreemat
subroutine threetreesbootcvbestpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootcvbestpruntreemattest
subroutine threetreesbootgammatreepruning(prunind,traindatasize,testdatasize,bestgammaval,cv,maxdepth,nodenummat,&
nodenummattest,allfval,prunenodenummat,prunenodenummattest)
	IMPLICIT NONE
	integer,intent(in) :: prunind,testdatasize,maxdepth,traindatasize,cv
	integer,intent(in) :: nodenummattest(testdatasize,maxdepth),nodenummat(traindatasize,maxdepth)
	double precision,intent(in) :: allfval((2**maxdepth)-1)
	double precision,intent(in) :: bestgammaval
	integer,intent(out) :: prunenodenummattest(testdatasize,maxdepth),prunenodenummat(traindatasize,maxdepth)
	double precision gammavec((2**(maxdepth-1))-1),allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	double precision minghval
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:),nodenummatnewtest(:,:),nodenummatnewsubtest(:,:)
	if(bestgammaval <= 0d0 .or. prunind==1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		prunenodenummattest(:,:) = nodenummattest(:,:)
		goto 5000
	endif
	gammavec(:) = 0d0
	call threetreesbootgterminalnodecount(nodenummat,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call threetreesbootgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	gammavec(1) = minghval
	if(gammavec(1) > bestgammaval .and. cv == -1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		prunenodenummattest(:,:) = nodenummattest(:,:)
		goto 5000
	endif
	allocate(nodenummatnew(traindatasize,maxdepth),nodenummatnewsub(traindatasize,maxdepth))
	allocate(nodenummatnewtest(testdatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
	call threetreesbootgpruntreemat(nodenummat,maxdepth,traindatasize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	call threetreesbootgpruntreemattest(nodenummattest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
	deallocate(nodenummatnewsub,nodenummatnewsubtest)
	if(bestgammaval == minghval .and. cv == 1) then
		prunenodenummat(:,:) = nodenummatnew(:,:)
		prunenodenummattest(:,:) = nodenummatnewtest(:,:)
		goto 5000
	endif
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesbootgterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			prunenodenummattest(:,:) = 0d0
			prunenodenummattest(:,1) = 1d0
			prunenodenummat(:,:) = 0d0
			prunenodenummat(:,1) = 1d0
			exit
		endif
		call threetreesbootgweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		gammavec(prunloop) = minghval
		if(gammavec(prunloop-1) < bestgammaval .and. gammavec(prunloop) > bestgammaval .and. cv == -1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			prunenodenummattest(:,:) = nodenummatnewtest(:,:)
			goto 5000
		endif
		allocate(nodenummatnewsub(traindatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
		call threetreesbootgpruntreemat(nodenummatnew,maxdepth,traindatasize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		call threetreesbootgpruntreemattest(nodenummatnewtest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub,nodenummatnewsubtest)
		if(bestgammaval == minghval .and. cv == 1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			prunenodenummattest(:,:) = nodenummatnewtest(:,:)
			goto 5000
		endif
	enddo
5000 continue
end subroutine threetreesbootgammatreepruning
subroutine threetreesbootgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesbootgterminalnodecount
subroutine threetreesbootgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesbootgweaknode
subroutine threetreesbootgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootgpruntreemat
subroutine threetreesbootgpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesbootgpruntreemattest
subroutine threetreesboottreepredict(datasizeori,datasizeboot,levelcount,maxdepth,prunenodenummatboot,&
prunenodenummatori,bootDATA,xydata,colnum,predvec,datatnnodenum)
	implicit none
	integer, intent(in) :: datasizeori,datasizeboot,levelcount,colnum,maxdepth
	integer, intent(in) :: prunenodenummatboot(datasizeboot,maxdepth),prunenodenummatori(datasizeori,maxdepth)
	double precision, intent(in) :: bootDATA(datasizeboot,colnum),XYDATA(datasizeori,colnum)
	integer, intent(out) :: datatnnodenum(datasizeori)
	double precision, intent(out) :: predvec(datasizeori)
	integer tndatacount((2**maxdepth)-1)
	integer i,j
	double precision, allocatable :: timepredsum(:,:),timepredcou(:,:)
	double precision tnodepredmat((2**maxdepth)-1,levelcount)
	allocate(timepredsum((2**maxdepth)-1,levelcount),timepredcou((2**maxdepth)-1,levelcount))
	timepredsum(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,datasizeboot
			if(sum(prunenodenummatboot(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(prunenodenummatboot(j,maxdepth) > 0) then
					timepredsum(prunenodenummatboot(j,maxdepth),int(bootDATA(j,3))) = &
					timepredsum(prunenodenummatboot(j,maxdepth),int(bootDATA(j,3))) + bootDATA(j,1)
					timepredcou(prunenodenummatboot(j,maxdepth),int(bootDATA(j,3))) = &
					timepredcou(prunenodenummatboot(j,maxdepth),int(bootDATA(j,3))) + 1d0
				endif
				cycle
			elseif(prunenodenummatboot(j,i) > 0 .and. prunenodenummatboot(j,i+1) == 0) then
				timepredsum(prunenodenummatboot(j,i),int(bootDATA(j,3))) = &
				timepredsum(prunenodenummatboot(j,i),int(bootDATA(j,3))) + bootDATA(j,1)
				timepredcou(prunenodenummatboot(j,i),int(bootDATA(j,3))) = &
				timepredcou(prunenodenummatboot(j,i),int(bootDATA(j,3))) + 1d0
			endif
		enddo
	enddo
3010 continue
	do i = 1,maxdepth
		if(sum(prunenodenummatori(:,i)) == 0) then
			goto 3020
		endif
		do j = 1,datasizeori
			if(i == maxdepth) then
				if(prunenodenummatori(j,maxdepth) > 0) then
					datatnnodenum(j) = prunenodenummatori(j,maxdepth)
				endif
				cycle
			endif
			if(prunenodenummatori(j,i) > 0 .and. prunenodenummatori(j,i+1) == 0) then
				datatnnodenum(j) = prunenodenummatori(j,i)
			endif
		enddo
	enddo
3020 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepredsum(i,:))) > 0d0) then
			do j = 1,levelcount
				tnodepredmat(i,j) = timepredsum(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,datasizeori
		predvec(i) = tnodepredmat(datatnnodenum(i),int(xydata(i,3)))
	enddo
end subroutine threetreesboottreepredict
subroutine threetreestreechoice(predvecmat,datatnnodenummat,msize,loops,levelcount,xydata,colnum,mins,&
bettertreenum,bettertreelossval,bettertreemaxval)
	implicit none
	integer, intent(in) :: msize,loops,levelcount,mins,colnum
	double precision, intent(in) :: predvecmat(msize,loops),xydata(msize,colnum)
	integer, intent(in) :: datatnnodenummat(msize,loops)
	double precision, intent(out) :: bettertreelossval(mins,5),bettertreemaxval(mins,5)
	integer, intent(out) :: bettertreenum(mins,6)
	double precision, allocatable :: randmat(:,:)
	integer ind1,ind2,ind3,samplesize,i,j
	integer combinations(3)
	integer losscomb(mins,3),randmaxcomb(mins,3)
	double precision lossvec(mins,5),randmaxvec(mins,5)
	double precision predmean(msize),randindexval,randval(3),lossval
	double precision worst_loss, worst_randmax
	integer worst_idx
	logical, allocatable :: has_split(:)
	allocate(randmat(loops,loops))
	allocate(has_split(loops))
	samplesize = msize/levelcount
	do i = 1,loops
		has_split(i) = .false.
		do j = 2,msize
			if(datatnnodenummat(j,i) /= datatnnodenummat(1,i)) then
				has_split(i) = .true.
				exit
			endif
		enddo
	enddo
	randmat(:,:) = 0d0
	do i = 1,loops
		if(.not. has_split(i)) cycle
		do j = (i+1),loops
			if(.not. has_split(j)) cycle
			call threetreesrandindex(samplesize,levelcount,datatnnodenummat(:,i),datatnnodenummat(:,j),msize,randindexval)
			if(isnan(randindexval)) then
				randmat(i,j) = 0d0
			else
				randmat(i,j) = randindexval
			endif
		enddo
	enddo
	lossvec(:,:) = 0d0
	randmaxvec(:,:) = 0d0
	losscomb(:,:) = 0
	randmaxcomb(:,:) = 0
	do i = 1,mins
		lossvec(i,1) = huge(1d0)
		randmaxvec(i,1) = huge(1d0)
		randmaxvec(i,3:5) = 2d0
	enddo
	do ind1 = 1, (loops-2)
		if(.not. has_split(ind1)) cycle
		do ind2 = (ind1 + 1), (loops-1)
			if(.not. has_split(ind2)) cycle
			do ind3 = (ind2 + 1), loops
				if(.not. has_split(ind3)) cycle
				combinations(1) = ind1 ; combinations(2) = ind2 ; combinations(3) = ind3
				predmean(:) = (predvecmat(:,ind1) + predvecmat(:,ind2) + predvecmat(:,ind3)) / 3d0
				lossval = sum((xydata(:,1) - predmean(:))*(xydata(:,1) - predmean(:))) / dble(samplesize)
				randval(1) = randmat(ind1,ind2)
				randval(2) = randmat(ind1,ind3)
				randval(3) = randmat(ind2,ind3)
				worst_loss = lossvec(1,1)
				worst_idx = 1
				do i = 2,mins
					if(lossvec(i,1) > worst_loss) then
						worst_loss = lossvec(i,1)
						worst_idx = i
					endif
				enddo
				if(lossval < worst_loss) then
					lossvec(worst_idx,1) = lossval
					losscomb(worst_idx,:) = combinations(:)
					lossvec(worst_idx,2) = 0d0
					lossvec(worst_idx,3:5) = randval(:)
				endif
				worst_randmax = maxval(randmaxvec(1,3:5))
				worst_idx = 1
				do i = 2,mins
					if(maxval(randmaxvec(i,3:5)) > worst_randmax) then
						worst_randmax = maxval(randmaxvec(i,3:5))
						worst_idx = i
					endif
				enddo
				if(maxval(randval(:)) < worst_randmax) then
					randmaxvec(worst_idx,1) = lossval
					randmaxcomb(worst_idx,:) = combinations(:)
					randmaxvec(worst_idx,2) = 0d0
					randmaxvec(worst_idx,3:5) = randval(:)
				endif
			enddo
		enddo
	enddo
	deallocate(randmat, has_split)
	do i = 1,mins
		bettertreenum(i,1:3) = losscomb(i,:)
		bettertreenum(i,4:6) = randmaxcomb(i,:)
	enddo
	bettertreelossval(:,:) = lossvec(:,:)
	bettertreemaxval(:,:) = randmaxvec(:,:)
end subroutine threetreestreechoice
subroutine threetreesrandindex(samplesize,levelcount,datatnnodenum,datatnnodenumtrue,msize,randindexval)
	implicit none
	integer, intent(in) :: msize,samplesize,levelcount
	integer, intent(in) :: datatnnodenum(msize),datatnnodenumtrue(msize)
	double precision, intent(out) :: randindexval
	integer tncount,tncounttrue,i,j,k
	integer datatnnodenumnorm(msize),datatnnodenumtruenorm(msize)
	integer subtnnodenumnorm(samplesize),subtnnodenumtruenorm(samplesize)
	double precision form1,form2,form3,form4,formval,rowsum,colsum,denom,num
	integer nz,r,c
	logical same
	double precision, allocatable :: tnval(:),tntrueval(:),conttable(:,:)
	call threetreestcdatasum(dble(datatnnodenum(:)),msize,tncount)
	call threetreestcdatasum(dble(datatnnodenumtrue(:)),msize,tncounttrue)
	allocate(tnval(tncount),tntrueval(tncounttrue))
	call threetreestcdataval(dble(datatnnodenum(:)),msize,tnval,tncount)
	call threetreestcdataval(dble(datatnnodenumtrue(:)),msize,tntrueval,tncounttrue)
	do i = 1,msize
		do j = 1,tncount
			if(datatnnodenum(i) == int(tnval(j))) then
				datatnnodenumnorm(i) = j
				exit
			endif
		enddo
		do k = 1,tncounttrue
			if(datatnnodenumtrue(i) == int(tntrueval(k))) then
				datatnnodenumtruenorm(i) = k
				exit
			endif
		enddo
	enddo
	j = 1
	do i = 1,samplesize
		subtnnodenumnorm(i) = datatnnodenumnorm(j)
		subtnnodenumtruenorm(i) = datatnnodenumtruenorm(j)
		j = j + levelcount
	enddo
	allocate(conttable(tncount,tncounttrue))
	conttable(:,:) = 0d0
	do i = 1,samplesize
		conttable(subtnnodenumnorm(i),subtnnodenumtruenorm(i)) = &
		conttable(subtnnodenumnorm(i),subtnnodenumtruenorm(i)) + 1d0
	enddo
	form1 = 0d0
	do i = 1,tncount
		do j = 1,tncounttrue
			formval = conttable(i,j)
			if(formval > 1d0) then
				form1 = form1 + formval * (formval - 1d0) / 2d0
			endif
		enddo
	enddo
	form2 = 0d0
	do i = 1,tncount
		rowsum = sum(conttable(i,:))
		if(rowsum > 1d0) then
			form2 = form2 + rowsum * (rowsum - 1d0) / 2d0
		endif
	enddo
	form3 = 0d0
	do j = 1,tncounttrue
		colsum = sum(conttable(:,j))
		if(colsum > 1d0) then
			form3 = form3 + colsum * (colsum - 1d0) / 2d0
		endif
	enddo
	form4 = dble(samplesize) * dble(samplesize - 1) / 2d0
	denom = 0.5d0 * (form2 + form3) - (form2 * form3) / form4
	num = form1 - (form2 * form3) / form4
	if(abs(denom) < 1d-15) then
		if(abs(num) > 1d-15) then
			randindexval = 0d0
		else
			same = .true.
			do r = 1, tncount
				nz = count(conttable(r,:) > 0d0)
				if(nz > 1) same = .false.
			enddo
			do c = 1, tncounttrue
				nz = count(conttable(:,c) > 0d0)
				if(nz > 1) same = .false.
			enddo
			if(same) then
				randindexval = 1d0
			else
				randindexval = 0d0
			endif
		endif
	else
		randindexval = num / denom
	endif
	deallocate(conttable,tnval,tntrueval)
end subroutine threetreesrandindex
subroutine threetreestcdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreestcdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreestcdatasum
recursive subroutine threetreestcdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreestcdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreestcdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreestcdatasort
subroutine threetreestcdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreestcdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreestcdataval
subroutine threetreestreegrowth(fixweight,maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,DATATYPE,beta1,beta2,&
	beta1len,beta2len,nodenummat,allfval,prunind,Rsplitmat)
	IMPLICIT NONE
	integer,intent(in) :: msize,colnum,levelcount,beta1len,beta2len,maxdepth,minsplit,minbucket
	integer,intent(in) :: datatype(colnum-3)
	double precision,intent(in) :: fixweight,alpha
	double precision,intent(in) :: xydata(msize,colnum),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: Rsplitmat((2**maxdepth)-1,10)
	double precision,intent(out) :: allfval((2**maxdepth)-1)
	integer,intent(out) :: prunind
	integer,intent(out) :: nodenummat(msize,maxdepth)
	double precision splitpval,weightval,weight,weightpval,splitwfval,splitweight,splitmcp,alphamcp
	double precision fval(2),splitfval(2),splitmcppval(2)
	integer nodenum, hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,sizenum,sizer,sizel,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5),nodenummatsub(msize,maxdepth)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:), splitindvec(:),nodesizesub(:)
	double precision,allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),xynodedata(:,:)
	double precision, allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer, allocatable :: flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	double precision :: splitgroupsum
	logical :: dfvec_set
	Rsplitmat(:,:) = 0.0d0
	nodenummat(:,:) = 0
	nodenummat(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2))
	prunind=0
	splitpval = 1d0
	call threetreessplitcount(msize, colnum-3, xydata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(msize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		call threetreessplitmat(ind1,datatype(ind1-3),xydata,msize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		do ind2 = 1,splitnum(ind1-3)
			indcou = indcou + 1
			indmat(indcou,1) = ind1
			indmat(indcou,2) = ind2
			call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),xydata,msize,colnum,ind1,anovadata,facvalout)
			call threetreesrepANOVA(msize,colnum,anovadata,fval,dfvec)
			fval_cache(indcou,1) = fval(1)
			fval_cache(indcou,2) = fval(2)
			groupsum_cache(indcou) = sum(anovadata(:,4))
			if (.not. dfvec_set) then
				dfvec_const = dfvec
				dfvec_set = .true.
			endif
			if(fixweight == -1.0d0) then
				do wcou = 0,10
					weightval = 0.1d0 * dble(wcou)
					wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				enddo
			else
				weightval = fixweight
				wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
			endif
		enddo
		deallocate(splitindmat,facvalout)
	enddo
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call threetreesweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(msize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = indmat(flat_idx,1)
				splitind2 = indmat(flat_idx,2)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreessplitmat(ind1,datatype(ind1-3),xydata,msize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			xydata,msize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call threetreesweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(msize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = indmat(flat_idx,1)
			splitind2 = indmat(flat_idx,2)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
		endif
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreessplitmat(ind1,datatype(ind1-3),xydata,msize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			xydata,msize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			deallocate(splitindmat,facvalout)
		endif
	endif
	if (splitpval >= 1d0) then
		prunind = 1
		goto 2002
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call threetreesweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call threetreesweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum <= dble(levelcount*minbucket) .or. &
	(dble(msize) - splitgroupsum) <= dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	Rsplitmat(1,1) =dble(nodenum)
	Rsplitmat(1,2) = splitweight
	Rsplitmat(1,3) = 1d0-splitweight
	Rsplitmat(1,4) = splitind1
	Rsplitmat(1,5) = splitind2
	Rsplitmat(1,6) = splitfval(1)
	Rsplitmat(1,7) = splitfval(2)
	Rsplitmat(1,8) = splitweight*splitfval(1) + (1-splitweight)*splitfval(2)
	Rsplitmat(1,9) = splitpval
	Rsplitmat(1,10) = splitmcp
	sizenum = size(splitfacval)
	call threetreesnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
	nodesize(1) = sizel
	nodesize(2) = sizer
	deallocate(anovadata)
	allfval(1) = splitwfval
	nodenummat(:,:) = nodenummatsub(:,:)
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call threetreesnodedatanumber(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize(nodeloop),xynodedata)
			call threetreessplitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			indcou = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) then
					deallocate(splitindmat)
				endif
				if(.not. allocated(splitindmat)) then
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				endif
				if(allocated(facvalout)) then
					deallocate(facvalout)
				endif
				if(.not. allocated(facvalout)) then
					allocate(facvalout(countvec(ind1-3)))
				endif
				call threetreessplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),&
				countvec(ind1-3),splitindmat)
				do ind2 = 1,splitnum(ind1-3)
					indcou = indcou + 1
					indmat(indcou,1) = ind1
					indmat(indcou,2) = ind2
					call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					call threetreesrepANOVA(nodesize(nodeloop),colnum,anovadata,fval,dfvec)
					fval_cache(indcou,1) = fval(1)
					fval_cache(indcou,2) = fval(2)
					groupsum_cache(indcou) = sum(anovadata(:,4))
					if (.not. dfvec_set) then
						dfvec_const = dfvec
						dfvec_set = .true.
					endif
					if(fixweight == -1.0d0) then
						do wcou = 0,10
							weightval = 0.1d0 * dble(wcou)
							wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						enddo
					else
						weightval = fixweight
						wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					endif
				enddo
				deallocate(splitindmat,facvalout)
2000			continue
			enddo
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call threetreesweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = indmat(flat_idx,1)
						splitind2 = indmat(flat_idx,2)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreessplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call threetreesweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = indmat(flat_idx,1)
					splitind2 = indmat(flat_idx,2)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
				endif
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreessplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreessplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					deallocate(splitindmat,facvalout)
				endif
			endif
			if (splitpval >= 1d0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call threetreesweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call threetreesweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum <= dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) <= dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			sizenum = size(splitfacval)
			call threetreesnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
			nodenummat(:,:) = nodenummatsub(:,:)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			Rsplitmat(nodenum,1) =dble(nodenum)
			Rsplitmat(nodenum,2) = splitweight
			Rsplitmat(nodenum,3) = 1d0-splitweight
			Rsplitmat(nodenum,4) = splitind1
			Rsplitmat(nodenum,5) = splitind2
			Rsplitmat(nodenum,6) = splitfval(1)
			Rsplitmat(nodenum,7) = splitfval(2)
			Rsplitmat(nodenum,8) = splitweight*splitfval(1) + (1-splitweight)*splitfval(2)
			Rsplitmat(nodenum,9) = splitpval
			Rsplitmat(nodenum,10) = splitmcp
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			deallocate(anovadata,xynodedata)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize)
		allocate(nodesize(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		deallocate(nodesizesub)
	enddo
2003 continue
	deallocate(nodesize)
2002 continue
end subroutine threetreestreegrowth
subroutine threetreesdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesdatasum
recursive subroutine threetreesdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesdatasort
subroutine threetreesdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreesdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreesdataval
subroutine threetreessplitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	double precision, intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	double precision datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call threetreesdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call threetreesdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine threetreessplitcount
subroutine threetreessplitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
end subroutine threetreessplitmat
subroutine threetreessplitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	double precision, intent(in) :: xydata(msize,colnum)
	double precision, intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	double precision facval(countvec)
	call threetreesdataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
			endif
		enddo
	enddo
end subroutine threetreessplitdata
subroutine threetreesrepANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	double precision, intent(in) :: anovadata(msize,4)
	double precision, intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	double precision ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	double precision ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	double precision, allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	double precision, allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine threetreesrepANOVA
subroutine threetreesweightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	double precision, intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: weightpval
	double precision DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	double precision xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call threetreespfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call threetreespfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call threetreesdemethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE threetreesweightedpval
subroutine threetreespfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	double precision,parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	double precision,intent(in)::a,b,eps,df1,df2,beta
	double precision,intent(out)::s
	double precision res,zval
	double precision inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine threetreespfdist
subroutine threetreesdemethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	double precision,intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    double precision,intent(out)::s
	integer,parameter::kmin=3, kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    double precision yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call threetreesdemethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call threetreesdemethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesdemethod
subroutine threetreesdemethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    double precision,intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    double precision,intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    double precision inv_weight
    double precision const_factor, df_ratio1, df_ratio2
    double precision df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    double precision v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesdemethod2
subroutine threetreesweightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	double precision,intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	double precision,intent(out) :: res
	double precision zval,form1,form2,form3,form4,form5,form6,form7,form8,form9,s1,s2,eps
	eps=1d-12
	s1 = 0d0
	s2 = 0d0
	zval = (z-((1d0-weight)*v))/weight
	form1 = 1d0 / weight
	form2 = 1d0 / beta1
	form3 = (df11/df12)**(df11/2d0)
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+((df11/df12)*zval))**((df11+df12)/2d0)
	form6 = 1d0 / beta2
	form7 = (df21/df22)**(df21/2d0)
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+((df21/df22)*v))**((df21+df22)/2d0)
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine threetreesweightfformula
subroutine threetreesnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,nodenummatsub,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	double precision, intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer,nodenummatsub(msize,maxdepth)
	integer i,j
	sizel=0
	sizer=0
	nodenummatsub(:,:) = nodenummat(:,:)
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummatsub(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummatsub(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine threetreesnodenumber
subroutine threetreesnodedatanumber(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,11)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine threetreesnodedatanumber
subroutine threetreescvtreepruning(prunind,msize,alpha,gamma,cv,maxdepth,nodenummat,allfval,allgammaval)
	IMPLICIT NONE
	integer,intent(in) :: prunind,msize,cv,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	double precision,intent(in) :: alpha,gamma,allfval((2**maxdepth)-1)
	double precision,intent(out) :: allgammaval((2**(maxdepth-1))-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision minghval,allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:)
	allgammaval(:) = 0d0
	if(prunind == 1 .or. alpha < 1d0 .or. gamma >= 0d0 .or. cv == -1) then
		goto 3001
	endif
	call threetreescvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call threetreescvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	allocate(nodenummatnew(msize,maxdepth),nodenummatnewsub(msize,maxdepth))
	call threetreescvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	deallocate(nodenummatnewsub)
	allgammaval(2) = minghval
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreescvterminalnodecount(nodenummatnew,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call threetreescvweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allocate(nodenummatnewsub(msize,maxdepth))
		call threetreescvpruntreemat(nodenummatnew,maxdepth,msize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub)
		allgammaval(prunloop+1) = minghval
	enddo
3001 continue
end subroutine threetreescvtreepruning
subroutine threetreescvterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreescvterminalnodecount
subroutine threetreescvweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreescvweaknode
subroutine threetreescvpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreescvpruntreemat
subroutine threetreesthreetreecv(gamma,alpha,cv,bootdata1,bootdata2,bootdata3,msize,colnum,Ksplit,levelcount,maxdepth,&
beta1,beta2,beta1len,beta2len,minbucket,minsplit,fixweight,datatype,allgammaval1,allgammaval2,allgammaval3,&
bestgammaval1,bestgammaval2,bestgammaval3,r2cvval1,r2cvval2,r2cvval3,r2cvvalthree,cvindin1,cvindin2,cvindin3,iseed)
	IMPLICIT NONE
	integer,intent(in) :: cv,msize,colnum,Ksplit,maxdepth,levelcount,beta1len,beta2len,minbucket,minsplit
	integer,intent(in) :: datatype(colnum-3)
	integer,intent(in) :: iseed
	double precision,intent(in) :: alpha,gamma,fixweight
	double precision,intent(in) :: beta1(beta1len),beta2(beta2len),allgammaval1((2**(maxdepth-1))-1),&
	allgammaval2((2**(maxdepth-1))-1),allgammaval3((2**(maxdepth-1))-1)
	integer,intent(in) :: cvindin1(msize),cvindin2(msize),cvindin3(msize)
	double precision,intent(in) :: bootdata1(msize,colnum),bootdata2(msize,colnum),bootdata3(msize,colnum)
	double precision,intent(out) :: bestgammaval1,bestgammaval2,bestgammaval3,r2cvval1,r2cvval2,r2cvval3,r2cvvalthree
	integer, allocatable :: cvind1(:),cvind2(:),cvind3(:),cvsize1(:),cvsize2(:),cvsize3(:)
	integer, allocatable ::  nodenummat1(:,:),nodenummat2(:,:),nodenummat3(:,:), &
	prunenodenummat1(:,:), prunenodenummat2(:,:), prunenodenummat3(:,:),&
	nodenummattest1(:,:),nodenummattest2(:,:),nodenummattest3(:,:),&
	nodenummattestcv1(:,:),nodenummattestcv2(:,:),nodenummattestcv3(:,:),&
	prunenodenummattest1(:,:),prunenodenummattest2(:,:),prunenodenummattest3(:,:)
	double precision, allocatable :: meangammacv1(:),meangammacv2(:),meangammacv3(:),meangammar2cv(:)
	double precision, allocatable :: gammacvmat1(:,:),gammacvmat2(:,:),gammacvmat3(:,:),traindata1(:,:),&
	traindata2(:,:),traindata3(:,:),&
	testdata1(:,:),testdata2(:,:),testdata3(:,:),testdataall(:,:),gammar2cvmat(:,:)
	integer cvloop,traindatasize1,traindatasize2,traindatasize3,testdatasize1,testdatasize2,testdatasize3,prunind1,&
	prunind2,prunind3,i,testdataallsize,bfsize,afsize
	double precision allfval1((2**maxdepth)-1),allfval2((2**maxdepth)-1),allfval3((2**maxdepth)-1),&
	gammacv1((2**(maxdepth-1))-1),gammacv2((2**(maxdepth-1))-1),gammacv3((2**(maxdepth-1))-1),&
	r2cvvalvec1(ksplit),r2cvvalvec2(ksplit),r2cvvalvec3(ksplit),&
	r2cvvalvecthree(ksplit),gammar2cv((2**(maxdepth-1))-1)
	double precision maxgammasub,r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub
	allocate(cvind1(msize),cvind2(msize),cvind3(msize),cvsize1(Ksplit),cvsize2(Ksplit),cvsize3(Ksplit),&
	gammacvmat1(ksplit,(2**(maxdepth-1))-1),gammacvmat2(ksplit,(2**(maxdepth-1))-1),gammacvmat3(ksplit,(2**(maxdepth-1))-1))
	allocate(gammar2cvmat(ksplit,(2**(maxdepth-1))-1),meangammacv1((2**(maxdepth-1))-1),&
	meangammacv2((2**(maxdepth-1))-1),meangammacv3((2**(maxdepth-1))-1))
	allocate(meangammar2cv((2**(maxdepth-1))-1))
	call threetreesttcvdata(bootdata1,msize,colnum,Ksplit,levelcount,cvindin1,cvind1,cvsize1,cv,iseed)
	call threetreesttcvdata(bootdata2,msize,colnum,Ksplit,levelcount,cvindin2,cvind2,cvsize2,cv,iseed)
	call threetreesttcvdata(bootdata3,msize,colnum,Ksplit,levelcount,cvindin3,cvind3,cvsize3,cv,iseed)
	do cvloop = 1,Ksplit
		traindatasize1 = ((sum(cvsize1)-cvsize1(cvloop))*levelcount)
		testdatasize1 = (cvsize1(cvloop)*levelcount)
		traindatasize2 = ((sum(cvsize2)-cvsize2(cvloop))*levelcount)
		testdatasize2 = (cvsize2(cvloop)*levelcount)
		traindatasize3 = ((sum(cvsize3)-cvsize3(cvloop))*levelcount)
		testdatasize3 = (cvsize3(cvloop)*levelcount)
		testdataallsize = testdatasize1+testdatasize2+testdatasize3
		allocate(traindata1(traindatasize1,colnum),traindata2(traindatasize2,colnum),traindata3(traindatasize3,colnum))
		allocate(testdata1(testdatasize1,colnum),testdata2(testdatasize2,colnum),testdata3(testdatasize3,colnum))
		allocate(testdataall(testdataallsize,colnum))
		allocate(nodenummat1(traindatasize1,maxdepth),nodenummat2(traindatasize2,maxdepth),nodenummat3(traindatasize3,maxdepth))
		allocate(nodenummattest1(testdataallsize,maxdepth),nodenummattest2(testdataallsize,maxdepth),&
		nodenummattest3(testdataallsize,maxdepth))
		allocate(nodenummattestcv1(testdatasize1,maxdepth),nodenummattestcv2(testdatasize2,maxdepth),&
		nodenummattestcv3(testdatasize3,maxdepth))
		call threetreesttcvdatachoice(bootdata1,msize,colnum,Ksplit,levelcount,cvloop,cvind1,cvsize1,traindata1,testdata1)
		call threetreesttcvdatachoice(bootdata2,msize,colnum,Ksplit,levelcount,cvloop,cvind2,cvsize2,traindata2,testdata2)
		call threetreesttcvdatachoice(bootdata3,msize,colnum,Ksplit,levelcount,cvloop,cvind3,cvsize3,traindata3,testdata3)
		testdataall(1:testdatasize1,:) = testdata1(:,:)
		testdataall((testdatasize1+1):(testdatasize1+testdatasize2),:) = testdata2(:,:)
		testdataall((testdatasize1+testdatasize2+1):testdataallsize,:) = testdata3(:,:)
		call threetreesttcvtreegrowth(traindatasize1,testdataallsize,traindata1,testdataall,nodenummattest1,fixweight,&
		maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata1,datatype,beta1,beta2,beta1len,&
		beta2len,nodenummat1,allfval1,prunind1)
		call threetreesttcvtreegrowth(traindatasize2,testdataallsize,traindata2,testdataall,nodenummattest2,fixweight,&
		maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata2,datatype,beta1,beta2,beta1len,&
		beta2len,nodenummat2,allfval2,prunind2)
		call threetreesttcvtreegrowth(traindatasize3,testdataallsize,traindata3,testdataall,nodenummattest3,fixweight,&
		maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata3,datatype,beta1,beta2,beta1len,&
		beta2len,nodenummat3,allfval3,prunind3)
		if(alpha < 1d0 .and. gamma < 0d0 .and. cv == -1) then
			call threetreesttbootpredict(cvloop,traindata1,traindata2,traindata3,traindatasize1,traindatasize2,traindatasize3,&
			nodenummat1,nodenummat2,nodenummat3,testdata1,testdata2,testdata3,testdataall,testdatasize1,&
			testdatasize2,testdatasize3,testdataallsize,&
			colnum,levelcount,nodenummattest1,nodenummattest2,nodenummattest3,maxdepth,&
			r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub)
			r2cvvalvec1(cvloop) = r2cvval1sub
			r2cvvalvec2(cvloop) = r2cvval2sub
			r2cvvalvec3(cvloop) = r2cvval3sub
			r2cvvalvecthree(cvloop) = r2cvvalthreesub
			bestgammaval1 = -1d0
			bestgammaval2 = -1d0
			bestgammaval3 = -1d0
		endif
		if(alpha == 1d0 .and. gamma >= 0d0 .and. cv == -1) then
			allocate(prunenodenummattest1(testdataallsize,maxdepth),prunenodenummattest2(testdataallsize,maxdepth),&
			prunenodenummattest3(testdataallsize,maxdepth))
			allocate(prunenodenummat1(traindatasize1,maxdepth),prunenodenummat2(traindatasize2,maxdepth),&
			prunenodenummat3(traindatasize3,maxdepth))
			call threetreesttcvgammatreepruning(prunind1,traindatasize1,testdataallsize,gamma,maxdepth,nodenummat1,&
			nodenummattest1,allfval1,prunenodenummat1,prunenodenummattest1)
			call threetreesttcvgammatreepruning(prunind2,traindatasize2,testdataallsize,gamma,maxdepth,nodenummat2,&
			nodenummattest2,allfval2,prunenodenummat2,prunenodenummattest2)
			call threetreesttcvgammatreepruning(prunind3,traindatasize3,testdataallsize,gamma,maxdepth,nodenummat3,&
			nodenummattest3,allfval3,prunenodenummat3,prunenodenummattest3)
			call threetreesttbootpredict(cvloop,traindata1,traindata2,traindata3,traindatasize1,traindatasize2,traindatasize3,&
			prunenodenummat1,prunenodenummat2,prunenodenummat3,testdata1,testdata2,testdata3,testdataall,&
			testdatasize1,testdatasize2,testdatasize3,testdataallsize,colnum,levelcount,prunenodenummattest1,&
			prunenodenummattest2,prunenodenummattest3,maxdepth,r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub)
			r2cvvalvec1(cvloop) = r2cvval1sub
			r2cvvalvec2(cvloop) = r2cvval2sub
			r2cvvalvec3(cvloop) = r2cvval3sub
			r2cvvalvecthree(cvloop) = r2cvvalthreesub
			bestgammaval1 = gamma
			bestgammaval2 = gamma
			bestgammaval3 = gamma
			deallocate(prunenodenummattest1,prunenodenummattest2,prunenodenummattest3)
			deallocate(prunenodenummat1,prunenodenummat2,prunenodenummat3)
		endif
		if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
			nodenummattestcv1(:,:) = nodenummattest1(1:testdatasize1,:)
			nodenummattestcv2(:,:) = nodenummattest2((testdatasize1+1):(testdatasize1+testdatasize2),:)
			nodenummattestcv3(:,:) = nodenummattest3((testdatasize1+testdatasize2+1):testdataallsize,:)
			call threetreesttcvbesttreepruning(traindatasize1,testdatasize1,maxdepth,nodenummat1,nodenummattestcv1,allfval1,&
			levelcount,colnum,traindata1,testdata1,allgammaval1,gammacv1)
			call threetreesttcvbesttreepruning(traindatasize2,testdatasize2,maxdepth,nodenummat2,nodenummattestcv2,allfval2,&
			levelcount,colnum,traindata2,testdata2,allgammaval2,gammacv2)
			call threetreesttcvbesttreepruning(traindatasize3,testdatasize3,maxdepth,nodenummat3,nodenummattestcv3,allfval3,&
			levelcount,colnum,traindata3,testdata3,allgammaval3,gammacv3)
			gammacvmat1(cvloop,:) = gammacv1(:)
			gammacvmat2(cvloop,:) = gammacv2(:)
			gammacvmat3(cvloop,:) = gammacv3(:)
		endif
		deallocate(traindata1,traindata2,traindata3,testdata1,testdata2,testdata3,testdataall)
		deallocate(nodenummat1,nodenummat2,nodenummat3,nodenummattest1,nodenummattest2,nodenummattest3)
		deallocate(nodenummattestcv1,nodenummattestcv2,nodenummattestcv3)
	enddo
	if(alpha == 1d0 .and. gamma < 0d0 .and. cv == 1) then
		do i = 1,size(allgammaval1)
			meangammacv1(i) = sum(gammacvmat1(:,i))
			if(meangammacv1(i) > 0) then
				meangammacv1(i) = meangammacv1(i) / dble(msize)
			else
				meangammacv1(i) = -1d0
			endif
		enddo
		maxgammasub = maxval(meangammacv1) + 1d0
		do i = 1,size(meangammacv1)
			if(meangammacv1(i) < maxgammasub .and. meangammacv1(i) >= 0d0) then
				bestgammaval1 = allgammaval1(i)
				maxgammasub = meangammacv1(i)
			endif
		enddo
		do i = 1,size(allgammaval2)
			meangammacv2(i) = sum(gammacvmat2(:,i))
			if(meangammacv2(i) > 0) then
				meangammacv2(i) = meangammacv2(i) / dble(msize)
			else
				meangammacv2(i) = -1d0
			endif
		enddo
		maxgammasub = maxval(meangammacv2) + 1d0
		do i = 1,size(meangammacv2)
			if(meangammacv2(i) < maxgammasub .and. meangammacv2(i) >= 0d0) then
				bestgammaval2 = allgammaval2(i)
				maxgammasub = meangammacv2(i)
			endif
		enddo
		do i = 1,size(allgammaval3)
			meangammacv3(i) = sum(gammacvmat3(:,i))
			if(meangammacv3(i) > 0) then
				meangammacv3(i) = meangammacv3(i) / dble(msize)
			else
				meangammacv3(i) = -1d0
			endif
		enddo
		maxgammasub = maxval(meangammacv3) + 1d0
		do i = 1,size(meangammacv3)
			if(meangammacv3(i) < maxgammasub .and. meangammacv3(i) >= 0d0) then
				bestgammaval3 = allgammaval3(i)
				maxgammasub = meangammacv3(i)
			endif
		enddo
		deallocate(cvind1,cvind2,cvind3,cvsize1,cvsize2,cvsize3)
		allocate(cvind1(msize),cvind2(msize),cvind3(msize),cvsize1(Ksplit),cvsize2(Ksplit),cvsize3(Ksplit))
		call threetreesttcvdata(bootdata1,msize,colnum,Ksplit,levelcount,cvindin1,cvind1,cvsize1,cv,iseed)
		call threetreesttcvdata(bootdata2,msize,colnum,Ksplit,levelcount,cvindin2,cvind2,cvsize2,cv,iseed)
		call threetreesttcvdata(bootdata3,msize,colnum,Ksplit,levelcount,cvindin3,cvind3,cvsize3,cv,iseed)
		do cvloop = 1,Ksplit
			traindatasize1 = ((sum(cvsize1)-cvsize1(cvloop))*levelcount)
			testdatasize1 = (cvsize1(cvloop)*levelcount)
			traindatasize2 = ((sum(cvsize2)-cvsize2(cvloop))*levelcount)
			testdatasize2 = (cvsize2(cvloop)*levelcount)
			traindatasize3 = ((sum(cvsize3)-cvsize3(cvloop))*levelcount)
			testdatasize3 = (cvsize3(cvloop)*levelcount)
			testdataallsize = testdatasize1+testdatasize2+testdatasize3
			allocate(traindata1(traindatasize1,colnum),traindata2(traindatasize2,colnum),traindata3(traindatasize3,colnum))
			allocate(testdata1(testdatasize1,colnum),testdata2(testdatasize2,colnum),testdata3(testdatasize3,colnum))
			allocate(testdataall(testdataallsize,colnum))
			allocate(nodenummat1(traindatasize1,maxdepth),nodenummat2(traindatasize2,maxdepth),nodenummat3(traindatasize3,maxdepth))
			allocate(nodenummattest1(testdataallsize,maxdepth),nodenummattest2(testdataallsize,maxdepth),&
			nodenummattest3(testdataallsize,maxdepth))
			call threetreesttcvdatachoice(bootdata1,msize,colnum,Ksplit,levelcount,cvloop,cvind1,cvsize1,traindata1,testdata1)
			call threetreesttcvdatachoice(bootdata2,msize,colnum,Ksplit,levelcount,cvloop,cvind2,cvsize2,traindata2,testdata2)
			call threetreesttcvdatachoice(bootdata3,msize,colnum,Ksplit,levelcount,cvloop,cvind3,cvsize3,traindata3,testdata3)
			testdataall(1:testdatasize1,:) = testdata1(:,:)
			testdataall((testdatasize1+1):(testdatasize1+testdatasize2),:) = testdata2(:,:)
			testdataall((testdatasize1+testdatasize2+1):testdataallsize,:) = testdata3(:,:)
			call threetreesttcvtreegrowth(traindatasize1,testdataallsize,traindata1,testdataall,nodenummattest1,fixweight,&
			maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata1,datatype,beta1,beta2,beta1len,&
			beta2len,nodenummat1,allfval1,prunind1)
			call threetreesttcvtreegrowth(traindatasize2,testdataallsize,traindata2,testdataall,nodenummattest2,fixweight,&
			maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata2,datatype,beta1,beta2,beta1len,&
			beta2len,nodenummat2,allfval2,prunind2)
			call threetreesttcvtreegrowth(traindatasize3,testdataallsize,traindata3,testdataall,nodenummattest3,fixweight,&
			maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,bootdata3,datatype,beta1,beta2,beta1len,&
			beta2len,nodenummat3,allfval3,prunind3)
			allocate(prunenodenummattest1(testdataallsize,maxdepth),prunenodenummattest2(testdataallsize,maxdepth),&
			prunenodenummattest3(testdataallsize,maxdepth))
			allocate(prunenodenummat1(traindatasize1,maxdepth),prunenodenummat2(traindatasize2,maxdepth),&
			prunenodenummat3(traindatasize3,maxdepth))
			call threetreesttcvgammatreepruning(prunind1,traindatasize1,testdataallsize,bestgammaval1,maxdepth,nodenummat1,&
			nodenummattest1,allfval1,prunenodenummat1,prunenodenummattest1)
			call threetreesttcvgammatreepruning(prunind2,traindatasize2,testdataallsize,bestgammaval2,maxdepth,nodenummat2,&
			nodenummattest2,allfval2,prunenodenummat2,prunenodenummattest2)
			call threetreesttcvgammatreepruning(prunind3,traindatasize3,testdataallsize,bestgammaval3,maxdepth,nodenummat3,&
			nodenummattest3,allfval3,prunenodenummat3,prunenodenummattest3)
			call threetreesttbootpredict(cvloop,traindata1,traindata2,traindata3,traindatasize1,traindatasize2,traindatasize3,&
			prunenodenummat1,prunenodenummat2,prunenodenummat3,testdata1,testdata2,testdata3,testdataall,&
			testdatasize1,testdatasize2,testdatasize3,testdataallsize,colnum,levelcount,prunenodenummattest1,&
			prunenodenummattest2,prunenodenummattest3,maxdepth,r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub)
			r2cvvalvec1(cvloop) = r2cvval1sub
			r2cvvalvec2(cvloop) = r2cvval2sub
			r2cvvalvec3(cvloop) = r2cvval3sub
			r2cvvalvecthree(cvloop) = r2cvvalthreesub
			deallocate(prunenodenummattest1,prunenodenummattest2,prunenodenummattest3)
			deallocate(prunenodenummat1,prunenodenummat2,prunenodenummat3)
			deallocate(traindata1,traindata2,traindata3,testdata1,testdata2,testdata3,testdataall)
			deallocate(nodenummat1,nodenummat2,nodenummat3,nodenummattest1,nodenummattest2,nodenummattest3)
		enddo
		r2cvval1=sum(r2cvvalvec1)/dble(ksplit)
		r2cvval2=sum(r2cvvalvec2)/dble(ksplit)
		r2cvval3=sum(r2cvvalvec3)/dble(ksplit)
		r2cvvalthree=sum(r2cvvalvecthree)/dble(ksplit)
	else
		r2cvval1=sum(r2cvvalvec1)/dble(ksplit)
		r2cvval2=sum(r2cvvalvec2)/dble(ksplit)
		r2cvval3=sum(r2cvvalvec3)/dble(ksplit)
		r2cvvalthree=sum(r2cvvalvecthree)/dble(ksplit)
	endif
end subroutine threetreesthreetreecv
subroutine threetreesttcvdata(XYDATA,msize,colnum,Ksplit,levelcount,cvindin,cvind,cvsize,cv,iseed)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,levelcount,cv
	integer, intent(in) :: iseed
	integer, intent(in) :: cvindin(msize)
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: cvind(msize), cvsize(Ksplit)
	integer i,subnum, randval, cvsizecou(Ksplit)
	integer, allocatable :: cvindsub(:)
	double precision randvalsub,ii
	integer :: seed_size, seed_i
	integer, allocatable :: seed_array(:)
	call random_seed(size=seed_size)
	allocate(seed_array(seed_size))
	do seed_i = 1, seed_size
		seed_array(seed_i) = iseed + (seed_i - 1) * 37
	enddo
	call random_seed(put=seed_array)
	deallocate(seed_array)
	subnum = msize/levelcount
	cvsize(:) = subnum/Ksplit
	do i = 1,(subnum - sum(cvsize))
		cvsize(i) = cvsize(i) + 1
	enddo
	if(cv==1) then
		cvind(:) = cvindin(:)
		goto 9000
	endif
	allocate(cvindsub(subnum))
	cvsizecou(:) = cvsize(:)
	do i = 1,subnum
		do
		    call random_number(randvalsub)
			randval = int(randvalsub * dble(Ksplit)) + 1
			if(cvsizecou(randval) > 0)then
				cvsizecou(randval) = cvsizecou(randval) - 1
				cvindsub(i) = randval
				exit
			endif
		enddo
	enddo
	do i = 1,subnum
		cvind((levelcount*(i-1)+1):(levelcount*i)) = cvindsub(i)
	enddo
9000 continue
end subroutine threetreesttcvdata
subroutine threetreesttcvdatachoice(XYDATA,msize,colnum,Ksplit,levelcount,testind,cvind,cvsize,traindata,testdata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,Ksplit,testind,levelcount
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: cvind(msize),cvsize(Ksplit)
	double precision, intent(out) :: traindata(((sum(cvsize)-cvsize(testind))*levelcount),colnum),&
	testdata((cvsize(testind)*levelcount),colnum)
	integer i,jtrain,jtest,subnum
	subnum = msize/levelcount
	jtest = 1
	jtrain = 1
	do i = 1,subnum
		if(cvind(((i-1)*levelcount)+1) == testind) then
			testdata((levelcount*(jtest-1)+1):(levelcount*jtest),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtest = jtest + 1
		else
			traindata((levelcount*(jtrain-1)+1):(levelcount*jtrain),:) = xydata((levelcount*(i-1)+1):(levelcount*i),:)
			jtrain = jtrain + 1
		endif
	enddo
end subroutine threetreesttcvdatachoice
subroutine threetreesttcvtreegrowth(traindatasize,testdatasize,traindata,testdata,nodenummattest,fixweight,&
maxdepth,minbucket,minsplit,alpha,msize,colnum,levelcount,xydata,datatype,beta1,beta2,beta1len,&
beta2len,nodenummat,allfval,prunind)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,beta1len,beta2len,levelcount,minsplit,minbucket,msize
	integer, intent(in) :: datatype(colnum-3)
	double precision, intent(in) :: fixweight,alpha
	double precision, intent(in) :: traindata(traindatasize,colnum),beta1(beta1len),beta2(beta2len)
	double precision, intent(in) :: xydata(msize,colnum),testdata(testdatasize,colnum)
	integer, intent(out) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	integer,intent(out) :: prunind
	double precision,intent(out) :: allfval((2**maxdepth)-1)
	integer nodenummatsub(traindatasize,maxdepth),nodenummatsubtest(testdatasize,maxdepth)
	integer nodenum,hierarchy,indcou,ind1,ind2,wcou,i,j,weightind,splitind1,splitind2,separatecou,separateint,sizenum
	integer sizel,sizer,sizeltest,sizertest,treeloop,stopcount,nodeloop
	integer splitnum(colnum-3),countvec(colnum-3),dfvec(5)
	double precision splitmcp,splitpval,weightval,weight,weightpval,splitweight,splitwfval,separatesp,alphamcp
	double precision fval(2),splitfval(2),splitmcppval(2)
	integer,allocatable :: nodesize(:),indmat(:,:),ind1vec(:),ind2vec(:),splitindmat(:,:),splitindvec(:),nodesizetest(:)
	integer,allocatable :: nodesizesub(:),nodesizesubtest(:)
	double precision, allocatable :: wfmat(:,:),wfvec(:),anovadata(:,:),facvalout(:),splitfacval(:),separateval(:)
	double precision, allocatable :: xynodedata(:,:),xynodedatatest(:,:)
	double precision, allocatable :: fval_cache(:,:), groupsum_cache(:)
	integer, allocatable :: flat_idx_vec(:)
	integer :: dfvec_const(5), flat_idx
	double precision :: splitgroupsum
	logical :: dfvec_set
	nodenummat(:,:) = 0
	nodenummat(:,1) = 1
	nodenummattest(:,:) = 0
	nodenummattest(:,1) = 1
	nodenum = 1
	hierarchy = 1
	allfval(:) = 0d0
	splitmcp = 0d0
	allocate(nodesize(2),nodesizetest(2))
	prunind=0
	splitpval = 1d0
	call threetreesttcvsplitcount(traindatasize, colnum-3, traindata, DATATYPE, splitnum, countvec)
	if(fixweight == -1.0d0) then
		allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
	else
		allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
	endif
	allocate(anovadata(traindatasize,4))
	allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
	dfvec_set = .false.
	indcou = 0
	do ind1=4,colnum
		allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
		call threetreesttcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,splitnum(ind1-3),countvec(ind1-3),splitindmat)
		do ind2 = 1,splitnum(ind1-3)
			indcou = indcou + 1
			indmat(indcou,1) = ind1
			indmat(indcou,2) = ind2
			call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			call threetreesttcvrepANOVA(traindatasize,colnum,anovadata,fval,dfvec)
			fval_cache(indcou,1) = fval(1)
			fval_cache(indcou,2) = fval(2)
			groupsum_cache(indcou) = sum(anovadata(:,4))
			if (.not. dfvec_set) then
				dfvec_const = dfvec
				dfvec_set = .true.
			endif
			if(fixweight == -1.0d0) then
				do wcou = 0,10
					weightval = 0.1d0 * dble(wcou)
					wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
				enddo
			else
				weightval = fixweight
				wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
			endif
		enddo
		deallocate(splitindmat,facvalout)
	enddo
	if(fixweight == -1.0d0) then
		allocate(flat_idx_vec(11))
		do i = 1,11
			j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
			wfvec(i) = wfmat(j,i)
			ind1vec(i) = indmat(j,1)
			ind2vec(i) = indmat(j,2)
			flat_idx_vec(i) = j
		enddo
	else
		allocate(flat_idx_vec(1))
		j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
		wfvec(1) = wfmat(j,1)
		ind1vec(1) = indmat(j,1)
		ind2vec(1) = indmat(j,2)
		flat_idx_vec(1) = j
	endif
	if(fixweight == -1.0d0) then
		do weightind=0,10
			flat_idx = flat_idx_vec(weightind+1)
			fval(1) = fval_cache(flat_idx, 1)
			fval(2) = fval_cache(flat_idx, 2)
			weight = 0.1d0 * dble(weightind)
			call threetreesttcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
			if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
			(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
				splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
				splitfval(1) = fval(1)
				splitfval(2) = fval(2)
				splitpval = weightpval
				splitind1 = indmat(flat_idx,1)
				splitind2 = indmat(flat_idx,2)
				splitweight = weight
				splitgroupsum = groupsum_cache(flat_idx)
			endif
			if(splitpval==0d0)then
				exit
			endif
		enddo
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesttcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesttcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesttcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	else
		flat_idx = flat_idx_vec(1)
		fval(1) = fval_cache(flat_idx, 1)
		fval(2) = fval_cache(flat_idx, 2)
		weight = fixweight
		call threetreesttcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
		(dble(traindatasize) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
			splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
			splitfval(1) = fval(1)
			splitfval(2) = fval(2)
			splitpval = weightpval
			splitind1 = indmat(flat_idx,1)
			splitind2 = indmat(flat_idx,2)
			splitweight = weight
			splitgroupsum = groupsum_cache(flat_idx)
		endif
		if (splitpval < 1d0) then
			ind1 = splitind1
			ind2 = splitind2
			allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
			call threetreesttcvsplitmat(ind1,datatype(ind1-3),traindata,traindatasize,colnum,&
			splitnum(ind1-3),countvec(ind1-3),splitindmat)
			call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
			traindata,traindatasize,colnum,ind1,anovadata,facvalout)
			if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
			allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
			splitfacval = facvalout
			splitindvec = splitindmat(ind2,:)
			if(datatype(splitind1-3) == 1) then
				call threetreesttcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
				allocate(separateval(separatecou))
				call threetreesttcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
				do separateint = 1,(size(splitindvec)-1)
					if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
						separatesp = splitfacval(separateint+1)
						exit
					endif
				enddo
				deallocate(splitfacval,splitindvec)
				allocate(splitfacval(separatecou),splitindvec(separatecou))
				splitfacval(:) = separateval(:)
				do separateint = 1,separatecou
					if(splitfacval(separateint) < separatesp) then
						splitindvec(separateint) = 0
					else
						splitindvec(separateint) = 1
					endif
				enddo
				deallocate(separateval)
			endif
			deallocate(splitindmat,facvalout)
		endif
	endif
	if (splitpval >= 1d0) then
		prunind = 1
		goto 2002
	endif
	if(fixweight == -1.0d0) then
		weight = 0d0
		call threetreesttcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(1) = 1d0 - weightpval
		weight = 1d0
		call threetreesttcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
		splitmcppval(2) = 1d0 - weightpval
		splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
		alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
		if(splitmcp > alphamcp) then
			prunind = 1
			goto 2002
		endif
	endif
	if(splitpval > alpha) then
		prunind = 1
		goto 2002
	endif
	if(splitgroupsum < dble(levelcount*minbucket) .or. &
	(dble(traindatasize) - splitgroupsum) < dble(levelcount*minbucket)) then
		prunind = 1
		goto 2002
	endif
	deallocate(fval_cache, groupsum_cache, flat_idx_vec)
	sizenum = size(splitfacval)
	call threetreesttcvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
	call threetreesttcvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum+1,&
	hierarchy+1,nodenummattest,nodenummatsubtest,sizeltest,sizertest)
	nodesize(1) = sizel
	nodesize(2) = sizer
	nodesizetest(1) = sizeltest
	nodesizetest(2) = sizertest
	deallocate(anovadata)
	allfval(1) = splitwfval
	nodenummat(:,:) = nodenummatsub(:,:)
	nodenummattest(:,:) = nodenummatsubtest(:,:)
	do treeloop = 1,(maxdepth-2)
		stopcount = 0
		hierarchy = hierarchy + 1
		do nodeloop = 1,(2**treeloop)
			if(allocated(wfmat) .or. allocated(indmat) .or. allocated(wfvec) .or. allocated(ind1vec) .or. allocated(ind2vec)) then
				deallocate(wfmat,indmat,wfvec,ind1vec,ind2vec)
			endif
			nodenum = nodenum + 1
			splitpval = 1d0
			allocate(xynodedata(nodesize(nodeloop),colnum),anovadata(nodesize(nodeloop),4),xynodedatatest(nodesizetest(nodeloop),colnum))
			if(nodesize(nodeloop) < (levelcount*minsplit)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			call threetreesttcvnodedata(traindata,traindatasize,colnum,nodenum,hierarchy,nodenummat,nodesize(nodeloop),xynodedata)
			call threetreesttcvnodedata(testdata,testdatasize,colnum,nodenum,hierarchy,nodenummattest,nodesizetest(nodeloop),xynodedatatest)
			call threetreesttcvsplitcount(nodesize(nodeloop), colnum-3, xynodedata, DATATYPE, splitnum, countvec)
			if(sum(splitnum) == 0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				allocate(wfmat(sum(splitnum),11),indmat(sum(splitnum),2),wfvec(11),ind1vec(11),ind2vec(11))
			else
				allocate(wfmat(sum(splitnum),1),indmat(sum(splitnum),2),wfvec(1),ind1vec(1),ind2vec(1))
			endif
			wfmat(:,:) = 0d0
			indmat(:,:) = 0
			indcou = 0
			allocate(fval_cache(sum(splitnum),2), groupsum_cache(sum(splitnum)))
			dfvec_set = .false.
			do ind1=4,colnum
				if(splitnum(ind1-3) == 0) then
					goto 2000
				endif
				if(allocated(splitindmat)) then
					deallocate(splitindmat)
				endif
				if(.not. allocated(splitindmat)) then
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)))
				endif
				if(allocated(facvalout)) then
					deallocate(facvalout)
				endif
				if(.not. allocated(facvalout)) then
					allocate(facvalout(countvec(ind1-3)))
				endif
				call threetreesttcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,splitnum(ind1-3),&
				countvec(ind1-3),splitindmat)
				do ind2 = 1,splitnum(ind1-3)
					indcou = indcou + 1
					indmat(indcou,1) = ind1
					indmat(indcou,2) = ind2
					call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),xynodedata,nodesize(nodeloop),&
					colnum,ind1,anovadata,facvalout)
					call threetreesttcvrepANOVA(nodesize(nodeloop),colnum,anovadata,fval,dfvec)
					fval_cache(indcou,1) = fval(1)
					fval_cache(indcou,2) = fval(2)
					groupsum_cache(indcou) = sum(anovadata(:,4))
					if (.not. dfvec_set) then
						dfvec_const = dfvec
						dfvec_set = .true.
					endif
					if(fixweight == -1.0d0) then
						do wcou = 0,10
							weightval = 0.1d0 * dble(wcou)
							wfmat(indcou,wcou+1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
						enddo
					else
						weightval = fixweight
						wfmat(indcou,1) = (weightval*fval(1)) + ((1d0-weightval)*fval(2))
					endif
				enddo
				deallocate(splitindmat,facvalout)
2000			continue
			enddo
			if(fixweight == -1.0d0) then
				allocate(flat_idx_vec(11))
				do i = 1,11
					j = maxloc(wfmat(1:sum(splitnum),i), dim=1)
					wfvec(i) = wfmat(j,i)
					ind1vec(i) = indmat(j,1)
					ind2vec(i) = indmat(j,2)
					flat_idx_vec(i) = j
				enddo
			else
				allocate(flat_idx_vec(1))
				j = maxloc(wfmat(1:sum(splitnum),1), dim=1)
				wfvec(1) = wfmat(j,1)
				ind1vec(1) = indmat(j,1)
				ind2vec(1) = indmat(j,2)
				flat_idx_vec(1) = j
			endif
			if(fixweight == -1.0d0) then
				do weightind=0,10
					flat_idx = flat_idx_vec(weightind+1)
					fval(1) = fval_cache(flat_idx, 1)
					fval(2) = fval_cache(flat_idx, 2)
					weight = 0.1d0 * dble(weightind)
					call threetreesttcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
					if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
					(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
						splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
						splitfval(1) = fval(1)
						splitfval(2) = fval(2)
						splitpval = weightpval
						splitind1 = indmat(flat_idx,1)
						splitind2 = indmat(flat_idx,2)
						splitweight = weight
						splitgroupsum = groupsum_cache(flat_idx)
					endif
					if(splitpval==0d0)then
						exit
					endif
				enddo
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesttcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesttcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesttcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			else
				flat_idx = flat_idx_vec(1)
				fval(1) = fval_cache(flat_idx, 1)
				fval(2) = fval_cache(flat_idx, 2)
				weight = fixweight
				call threetreesttcvweightedpval(weight,fval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				if(splitpval > weightpval .and. groupsum_cache(flat_idx) > dble(levelcount*minbucket) .and. &
				(dble(nodesize(nodeloop)) - groupsum_cache(flat_idx)) > dble(levelcount*minbucket)) then
					splitwfval = weight*fval(1) + (1d0-weight)*fval(2)
					splitfval(1) = fval(1)
					splitfval(2) = fval(2)
					splitpval = weightpval
					splitind1 = indmat(flat_idx,1)
					splitind2 = indmat(flat_idx,2)
					splitweight = weight
					splitgroupsum = groupsum_cache(flat_idx)
				endif
				if (splitpval < 1d0) then
					ind1 = splitind1
					ind2 = splitind2
					allocate(splitindmat(splitnum(ind1-3),countvec(ind1-3)), facvalout(countvec(ind1-3)))
					call threetreesttcvsplitmat(ind1,datatype(ind1-3),xynodedata,nodesize(nodeloop),colnum,&
					splitnum(ind1-3),countvec(ind1-3),splitindmat)
					call threetreesttcvsplitdata(splitindmat(ind2,:),countvec(ind1-3),&
					xynodedata,nodesize(nodeloop),colnum,ind1,anovadata,facvalout)
					if(allocated(splitfacval)) deallocate(splitfacval,splitindvec)
					allocate(splitfacval(countvec(ind1-3)),splitindvec(countvec(ind1-3)))
					splitfacval = facvalout
					splitindvec = splitindmat(ind2,:)
					if(datatype(splitind1-3) == 1) then
						call threetreesttcvdatasum(testdata(:,splitind1),testdatasize,separatecou)
						allocate(separateval(separatecou))
						call threetreesttcvdataval(testdata(:,splitind1),testdatasize,separateval,separatecou)
						do separateint = 1,(size(splitindvec)-1)
							if(abs(splitindvec(separateint+1) - splitindvec(separateint)) > 0d0) then
								separatesp = splitfacval(separateint+1)
								exit
							endif
						enddo
						deallocate(splitfacval,splitindvec)
						allocate(splitfacval(separatecou),splitindvec(separatecou))
						splitfacval(:) = separateval(:)
						do separateint = 1,separatecou
							if(splitfacval(separateint) < separatesp) then
								splitindvec(separateint) = 0
							else
								splitindvec(separateint) = 1
							endif
						enddo
						deallocate(separateval)
					endif
					deallocate(splitindmat,facvalout)
				endif
			endif
			if (splitpval >= 1d0) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(fixweight == -1.0d0) then
				weight = 0d0
				call threetreesttcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(1) = 1d0 - weightpval
				weight = 1d0
				call threetreesttcvweightedpval(weight,splitfval,dfvec_const,beta1,beta2,beta1len,beta2len,weightpval)
				splitmcppval(2) = 1d0 - weightpval
				splitmcp = 1d0 - (splitmcppval(1) * splitmcppval(2))
				alphamcp = 1d0-((1d0-alpha)*(1d0-alpha))
				if(splitmcp > alphamcp) then
					stopcount = stopcount + 1
					goto 2001
				endif
			endif
			if(splitpval > alpha) then
				stopcount = stopcount + 1
				goto 2001
			endif
			if(splitgroupsum < dble(levelcount*minbucket) .or. &
			(dble(nodesize(nodeloop)) - splitgroupsum) < dble(levelcount*minbucket)) then
				stopcount = stopcount + 1
				goto 2001
			endif
			allfval(nodenum) = splitwfval
			if(.not. allocated(nodesizesub)) then
				allocate(nodesizesub(2**hierarchy))
				nodesizesub(:) = 0
			endif
			if(.not. allocated(nodesizesubtest)) then
				allocate(nodesizesubtest(2**hierarchy))
				nodesizesubtest(:) = 0
			endif
			sizenum = size(splitfacval)
			call threetreesttcvnodenumber(traindata,maxdepth,traindatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummat,nodenummatsub,sizel,sizer)
			call threetreesttcvnodenumber(testdata,maxdepth,testdatasize,colnum,splitfacval,splitindvec,sizenum,splitind1,nodenum*2,&
			hierarchy+1,nodenummattest,nodenummatsubtest,sizeltest,sizertest)
			nodenummat(:,:) = nodenummatsub(:,:)
			nodenummattest(:,:) = nodenummatsubtest(:,:)
			nodesizesub(2*nodeloop-1) = sizel
			nodesizesub(2*nodeloop) = sizer
			nodesizesubtest(2*nodeloop-1) = sizeltest
			nodesizesubtest(2*nodeloop) = sizertest
2001		continue
			if(allocated(fval_cache)) deallocate(fval_cache, groupsum_cache, flat_idx_vec)
			deallocate(anovadata,xynodedata,xynodedatatest)
			if(stopcount == 2**treeloop) then
				goto 2003
			endif
		enddo
		deallocate(nodesize,nodesizetest)
		allocate(nodesize(2**hierarchy),nodesizetest(2**hierarchy))
		nodesize(:) = nodesizesub(:)
		nodesizetest(:) = nodesizesubtest(:)
		deallocate(nodesizesub,nodesizesubtest)
	enddo
2003 continue
	deallocate(nodesize,nodesizetest)
2002 continue
end subroutine threetreesttcvtreegrowth
subroutine threetreesttcvsplitcount(samplesize, pp, sampledata, DATATYPE, splitnum,countvec)
	IMPLICIT NONE
	integer, intent(in) :: samplesize, pp
	double precision, intent(in) :: sampledata(samplesize,pp+3)
	integer, intent(in) :: datatype(pp)
	integer, intent(out) :: splitnum(pp), countvec(pp)
	double precision datasample(samplesize), sortsample(samplesize)
	integer i, j, count, facsum
	do i = 4,pp+3
		datasample = sampledata(:,i)
		if(datatype(i-3) == 1) then
			call threetreesttcvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = facsum - 1
		elseif(datatype(i-3) == 2) then
			call threetreesttcvdatasum(sampledata(:,i),samplesize,facsum)
			splitnum(i-3) = (2 ** (facsum-1)) - 1
		endif
		countvec(i-3) = facsum
	enddo
end subroutine threetreesttcvsplitcount
subroutine threetreesttcvdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesttcvdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesttcvdatasum
recursive subroutine threetreesttcvdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesttcvdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesttcvdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesttcvdatasort
subroutine threetreesttcvsplitmat(varnum,datatype,xydata,msize,colnum,splitnum,countvec,splitindmat)
	IMPLICIT NONE
	integer, intent(in) :: varnum,datatype,msize,colnum,splitnum,countvec
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(out) :: splitindmat(splitnum,countvec)
	integer i,j,splitindmat1(splitnum,2), count_0, count_1, idx
	if(datatype == 1) then
		do i = 1,splitnum
			do j = 1,countvec
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype == 2) then
	    idx = 1	
		do i = 0, 2**(countvec-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, countvec - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
end subroutine threetreesttcvsplitmat
subroutine threetreesttcvsplitdata(splitindmat,countvec,xydata,msize,colnum,ind1,anovadata,facvalout)
	IMPLICIT NONE
	integer, intent(in) :: countvec,msize,colnum,ind1
	integer, intent(in) :: splitindmat(countvec)
	double precision, intent(in) :: xydata(msize,colnum)
	double precision, intent(out) :: anovadata(msize,4),facvalout(countvec)
	integer i,j
	double precision facval(countvec)
	call threetreesttcvdataval(xydata(:,ind1),msize,facval,countvec)
	facvalout = facval
	do i = 1,msize
		do j = 1,countvec
			if(xydata(i,ind1) == facval(j)) then
				anovadata(i,1:3) = xydata(i,1:3)
				anovadata(i,4) = splitindmat(j)
			endif
		enddo
	enddo
end subroutine threetreesttcvsplitdata
subroutine threetreesttcvrepANOVA(msize, pp, anovadata, fval, dfvec)
	IMPLICIT NONE
	integer,intent(in) :: msize, pp
	double precision, intent(in) :: anovadata(msize,4)
	double precision, intent(OUT) :: fval(2)
	integer, intent(OUT) :: dfvec(5)
	integer i, gi, ti, si, max_subj_id, timecount, nsubjects
	double precision ymean, sstotal, ssgroup, sstime, ssgrouptime, sssubject, sserr
	double precision ms(5)
	integer, allocatable :: subj_map(:), si_arr(:)
	double precision, allocatable :: ygroup(:), ytime(:), ysubject(:), ygrouptime(:,:)
	double precision, allocatable :: ygroupcount(:), ytimecount(:), ysubjectcount(:), ygrouptimecount(:,:)
	timecount = nint(maxval(anovadata(:,3)))
	max_subj_id = nint(maxval(anovadata(:,2)))
	allocate(subj_map(max_subj_id))
	subj_map(:) = 0
	do i = 1, msize
		subj_map(nint(anovadata(i,2))) = 1
	enddo
	nsubjects = 0
	do i = 1, max_subj_id
		if (subj_map(i) > 0) then
			nsubjects = nsubjects + 1
			subj_map(i) = nsubjects
		endif
	enddo
	dfvec(1) = 1
	dfvec(2) = timecount - 1
	dfvec(3) = timecount - 1
	dfvec(4) = nsubjects - 2
	dfvec(5) = (timecount - 1) * (nsubjects - 2)
	allocate(ygroup(2), ytime(timecount), ysubject(nsubjects), ygrouptime(2, timecount))
	allocate(ygroupcount(2), ytimecount(timecount), ysubjectcount(nsubjects), ygrouptimecount(2, timecount))
	allocate(si_arr(msize))
	ygroup(:) = 0d0; ytime(:) = 0d0; ysubject(:) = 0d0; ygrouptime(:,:) = 0d0
	ygroupcount(:) = 0d0; ytimecount(:) = 0d0; ysubjectcount(:) = 0d0; ygrouptimecount(:,:) = 0d0
	ymean = sum(anovadata(:,1)) / msize
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = subj_map(nint(anovadata(i,2)))
		si_arr(i) = si
		ygroup(gi) = ygroup(gi) + anovadata(i,1)
		ygroupcount(gi) = ygroupcount(gi) + 1d0
		ytime(ti) = ytime(ti) + anovadata(i,1)
		ytimecount(ti) = ytimecount(ti) + 1d0
		ysubject(si) = ysubject(si) + anovadata(i,1)
		ysubjectcount(si) = ysubjectcount(si) + 1d0
		ygrouptime(gi,ti) = ygrouptime(gi,ti) + anovadata(i,1)
		ygrouptimecount(gi,ti) = ygrouptimecount(gi,ti) + 1d0
	enddo
	ygroup = ygroup / ygroupcount
	ytime = ytime / ytimecount
	ysubject = ysubject / ysubjectcount
	ygrouptime = ygrouptime / ygrouptimecount
	sstotal = 0d0; ssgroup = 0d0; sstime = 0d0
	ssgrouptime = 0d0; sssubject = 0d0
	do i = 1, msize
		gi = nint(anovadata(i,4)) + 1
		ti = nint(anovadata(i,3))
		si = si_arr(i)
		sstotal = sstotal + (anovadata(i,1) - ymean)**2
		ssgroup = ssgroup + (ygroup(gi) - ymean)**2
		sstime = sstime + (ytime(ti) - ymean)**2
		ssgrouptime = ssgrouptime + (ygrouptime(gi,ti) - ygroup(gi) - ytime(ti) + ymean)**2
		sssubject = sssubject + (ysubject(si) - ygroup(gi))**2
	enddo
	sserr = sstotal - (ssgroup + sstime + ssgrouptime + sssubject)
	ms(1) = ssgroup / dfvec(1)
	ms(2) = sstime / dfvec(2)
	ms(3) = ssgrouptime / dfvec(3)
	ms(4) = sssubject / dfvec(4)
	ms(5) = sserr / dfvec(5)
	fval(1) = ms(1) / ms(4)
	fval(2) = ms(3) / ms(5)
	deallocate(subj_map, si_arr)
	deallocate(ygroup, ytime, ysubject, ygrouptime)
	deallocate(ygroupcount, ytimecount, ysubjectcount, ygrouptimecount)
end subroutine threetreesttcvrepANOVA
subroutine threetreesttcvweightedpval(weight,fval,dfvec,beta1,beta2,beta1len,beta2len,weightpval)
	IMPLICIT NONE
	integer, intent(in) :: dfvec(5),beta1len,beta2len
	double precision, intent(in) :: weight, fval(2),beta1(beta1len),beta2(beta2len)
	double precision, intent(out) :: weightpval
	double precision DFD1, DFN1, DFD2, DFN2, TESTVAL1, TESTVAL2
	double precision xb,eps,s
	eps = 1d-12
	DFD1 = dble(dfvec(1))
	DFN1 = dble(dfvec(4))
	DFD2 = dble(dfvec(3))
	DFN2 = dble(dfvec(5))
	TESTVAL1 = fval(1)
	TESTVAL2 = fval(2)
	if(abs(weight - 1d0) < 1d-15) then
		s=0d0
		call threetreesttcvpfdist(DFD1,DFN1,0d0,TESTval1,eps,beta1(int(DFN1)),s)
		weightpval = 1.0d0 - s
		goto 10000
	elseif(abs(weight) < 1d-15) then
		s=0d0
		call threetreesttcvpfdist(DFD2,DFN2,0d0,TESTval2,eps,beta2(int(DFN2)),s)
		weightpval = 1.0d0 - s
		goto 10000
	endif
	xb = (weight*TESTVAL1) + ((1d0-weight)*TESTVAL2)
	s=0d0
	call threetreesttcvdemethod(xb,weight,DFD1,DFN1,DFD2,DFN2,eps,beta1(int(DFN1)),beta2(int(DFN2)),s)
	weightpval = 1d0-s
10000 continue
	weightpval = max(0d0, min(1d0, weightpval))
END SUBROUTINE threetreesttcvweightedpval
subroutine threetreesttcvpfdist(df1,df2,a,b,eps,beta,s)
	implicit none
	integer,parameter::kmin=3,kmax=14
	double precision,parameter::hr=6.d0, c0=0.01d0, pi2=1.5707963267948966d0
	double precision,intent(in)::a,b,eps,df1,df2,beta
	double precision,intent(out)::s
	double precision res,zval
	double precision inv_beta, df_ratio, df1_half, df12_half, form3, df1m2_half
    integer::j,nc,l
	double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps
	inv_beta = 1d0 / beta
	df_ratio = df1/df2
	df1_half = df1/2d0
	df12_half = (df1+df2)/2d0
	form3 = df_ratio**df1_half
	df1m2_half = (df1-2d0)/2d0
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(b-a)*0.5d0
    pba=(b+a)*0.5d0
	zval = pba
	res = inv_beta * form3 * (zval**df1m2_half) / &
		  ((1d0+(df_ratio*zval))**df12_half)
    s0=res*h*pi2*mba
    s=0d0    
    nc=1
    do l=2,kmax
		s=0d0
		nc=2*nc
		h=h*0.5d0
		do j=1,nc
			t=dble(2*j-nc-1)*h
			shk=pi2*sinh(t)
			xt=tanh(shk)
			wt=pi2*cosh(t)*(1d0 - xt*xt)
			zval = mba*xt+pba
			res = inv_beta * form3 * (zval**df1m2_half) / &
				  ((1d0+(df_ratio*zval))**df12_half)
			s=s+res*wt
		enddo
		s=s0*0.5d0+s*h*mba
		as=abs(s); err=abs(s-s0)
		if(as.ge.1d0)err=err/as      
		if(err.le.seps.and.l.ge.kmin)exit
		s0=s
	enddo
end subroutine threetreesttcvpfdist
subroutine threetreesttcvdemethod(xb,weight,df11,df12,df21,df22,eps,beta1,beta2,s)
	implicit none  
	double precision,intent(in)::xb,weight,df11,df12,df21,df22,eps,beta1,beta2
    double precision,intent(out)::s
	integer,parameter::kmin=3, kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0
    integer::j,nc,l
    double precision yb,res,err,ft,h,s0,xt,wt,t,as,shk,mba,pba,seps
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    mba=(xb-0d0)*0.5d0
    pba=(xb+0d0)*0.5d0
    call threetreesttcvdemethod2(weight,df11,df12,df21,df22,pba,eps,beta1,beta2,ft)
    s0=ft*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          call threetreesttcvdemethod2(weight,df11,df12,df21,df22,mba*xt+pba,eps,beta1,beta2,ft)
          s=s+ft*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as
       if(err.le.seps.and.l.ge.kmin)exit
	   if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesttcvdemethod
subroutine threetreesttcvdemethod2(weight,df11,df12,df21,df22,e,eps,beta1,beta2,s)
    implicit none
    double precision,intent(in)::weight,df11,df12,df21,df22,e,eps,beta1,beta2
    double precision,intent(out)::s
    integer j,nc,l
	integer,parameter::kmin=3,kmax=8
	double precision,parameter::hr=6.0d0,c0=0.01d0,pi2=1.5707963267948966d0  
    double precision h,s0,xt,wt,t,as,shk,mba,pba,err,seps,bw,res
    double precision inv_weight
    double precision const_factor, df_ratio1, df_ratio2
    double precision df1m2_half, df2m2_half, df12_sum_half, df22_sum_half
    double precision v, zval
	inv_weight = 1d0-weight
    df_ratio1 = df11/df12
    df_ratio2 = df21/df22
    df1m2_half = (df11-2d0)/2d0
    df2m2_half = (df21-2d0)/2d0
    df12_sum_half = (df11+df12)/2d0
    df22_sum_half = (df21+df22)/2d0
    const_factor = (1d0/weight) * (1d0/beta1) * (df_ratio1**(df11/2d0)) * &
                   (1d0/beta2) * (df_ratio2**(df21/2d0))
    seps=c0*sqrt(eps)
    h=hr*0.5d0
    bw = e / inv_weight
    mba=(bw-0d0)*0.5d0
    pba=(bw+0d0)*0.5d0
    v = pba
    zval = (e - inv_weight*v)/weight
    res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
          (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
    s0=res*h*pi2*mba
    s=0d0
    nc=1
    do l=2,kmax
       s=0d0
       nc=2*nc
       h=h*0.5d0
       do j=1,nc
          t=dble(2*j-nc-1)*h
          shk=pi2*sinh(t)
          xt=tanh(shk)
          wt=pi2*cosh(t)*(1d0 - xt*xt)
          v = mba*xt+pba
          zval = (e - inv_weight*v)/weight
          res = const_factor * (zval**df1m2_half) / ((1d0+df_ratio1*zval)**df12_sum_half) * &
                (v**df2m2_half) / ((1d0+df_ratio2*v)**df22_sum_half)
		  s=s+res*wt
       enddo
       s=s0*0.5d0+s*h*mba
       as=abs(s); err=abs(s-s0)
       if(as.ge.1d0)err=err/as             
       if(err.le.seps.and.l.ge.kmin)exit
       if(err.le.0.000001d0 .and. l>6)exit
       s0=s
    enddo
end subroutine threetreesttcvdemethod2
subroutine threetreesttcvweightfformula(z,v,weight,df11,df12,df21,df22,beta1,beta2,res)
	implicit none
	double precision,intent(in) :: z,v,weight,df11,df12,df21,df22,beta1,beta2
	double precision,intent(out) :: res
	double precision zval,form1,form2,form3,form4,form5,form6,form7,form8,form9,s1,s2,eps
	eps=1d-12
	s1 = 0d0
	s2 = 0d0
	zval = (z-((1d0-weight)*v))/weight
	form1 = 1d0 / weight
	form2 = 1d0 / beta1
	form3 = (df11/df12)**(df11/2d0)
	form4 = zval**((df11-2d0)/2d0)
	form5 = (1d0+((df11/df12)*zval))**((df11+df12)/2d0)
	form6 = 1d0 / beta2
	form7 = (df21/df22)**(df21/2d0)
	form8 = v**((df21-2d0)/2d0)
	form9 = (1d0+((df21/df22)*v))**((df21+df22)/2d0)
	res = form1 * (form2 * form3 * form4 / form5) * (form6 * form7 * form8 / form9)
end subroutine threetreesttcvweightfformula
subroutine threetreesttcvdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreesttcvdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreesttcvdataval
subroutine threetreesttcvnodenumber(xydata,maxdepth,msize,colnum,splitfacval,splitindvec,sizenum,splitind1,&
nodenum,hierarchy,nodenummat,nodenummatsub,sizel,sizer)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,sizenum,splitind1,nodenum,splitindvec(sizenum),hierarchy,maxdepth
	double precision, intent(in) :: xydata(msize,colnum),splitfacval(sizenum)
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: sizel,sizer,nodenummatsub(msize,maxdepth)
	integer i,j
	sizel=0
	sizer=0
	nodenummatsub(:,:) = nodenummat(:,:)
	do i = 1,msize
		if(nodenummat(i,hierarchy-1) == (nodenum/2)) then
			do j = 1,sizenum
				if(abs(xydata(i,splitind1) - splitfacval(j)) < (1.0d0*(10d0**(-10d0)))) then
					if(splitindvec(j) == 0) then
						nodenummatsub(i,hierarchy) = nodenum
						sizel=sizel+1
					elseif(splitindvec(j) == 1) then
						nodenummatsub(i,hierarchy) = nodenum + 1
						sizer=sizer+1
					endif
				endif
			enddo
		endif
	enddo
end subroutine threetreesttcvnodenumber
subroutine threetreesttcvnodedata(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,11)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine threetreesttcvnodedata
subroutine threetreesttR2CV(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
nodenummattest,testdatasize,maxdepth,r2cvval)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,levelcount
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	double precision, intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	double precision, intent(out) :: r2cvval
	double precision, allocatable :: timepred(:,:),r2cvnumsub(:,:), timepredcou(:,:)
	double precision r2cvnum,r2cvden,ymean
	integer i,j,k,l
	allocate(timepred(((2**maxdepth)-1),levelcount),r2cvnumsub(((2**maxdepth)-1),levelcount))
	allocate(timepredcou(((2**maxdepth)-1),levelcount))
	timepred(:,:) = 0d0
	r2cvnumsub(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize
			if(sum(nodenummat(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(nodenummat(j,maxdepth) > 0) then
					timepred(nodenummat(j,maxdepth),int(traindata(j,3))) = timepred(nodenummat(j,maxdepth),int(traindata(j,3))) + traindata(j,1)
					timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) = timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) + 1d0
				endif
				cycle
			endif
			if(nodenummat(j,i) > 0 .and. nodenummat(j,i+1) == 0) then
				timepred(nodenummat(j,i),int(traindata(j,3))) = timepred(nodenummat(j,i),int(traindata(j,3))) + traindata(j,1)
				timepredcou(nodenummat(j,i),int(traindata(j,3))) = timepredcou(nodenummat(j,i),int(traindata(j,3))) + 1d0
			endif
		enddo
	enddo
3010 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	ymean = sum(testdata(:,1))/dble(testdatasize)
	r2cvnum = 0d0
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j=1,maxdepth
				if(2**(j-1) <= i .and. i < 2**j) then
					k = j
					exit
				endif
			enddo
			do l = 1,testdatasize
				if(nodenummattest(l,k) == i) then
					r2cvnumsub(i,int(testdata(l,3))) = r2cvnumsub(i,int(testdata(l,3))) + ((testdata(l,1) - timepred(i,int(testdata(l,3))))**2)
				endif
			enddo
		endif
	enddo
	r2cvnum = sum(r2cvnumsub)
	r2cvden = 0d0
	do i = 1,testdatasize
		r2cvden = r2cvden + ((testdata(i,1) - ymean) * (testdata(i,1) - ymean))
	enddo
	r2cvval = 1d0-(r2cvnum/r2cvden)
	deallocate(timepred,r2cvnumsub,timepredcou)
end subroutine threetreesttR2CV
subroutine threetreesttcvgammatreepruning(prunind,traindatasize,testdatasize,gamma,maxdepth,nodenummat,nodenummattest,&
allfval,prunenodenummat,prunenodenummattest)
	IMPLICIT NONE
	integer,intent(in) :: prunind,testdatasize,maxdepth,traindatasize
	integer,intent(in) :: nodenummattest(testdatasize,maxdepth),nodenummat(traindatasize,maxdepth)
	double precision,intent(in) :: allfval((2**maxdepth)-1)
	double precision,intent(in) :: gamma
	integer,intent(out) :: prunenodenummat(traindatasize,maxdepth),prunenodenummattest(testdatasize,maxdepth)
	double precision gammavec((2**(maxdepth-1))-1),allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	double precision minghval
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:),nodenummatnewtest(:,:),nodenummatnewsubtest(:,:)
	if(prunind==1) then
		prunenodenummattest(:,:) = nodenummattest(:,:)
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	gammavec(:) = 0d0
	call threetreesttcvgterminalnodecount(nodenummat,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call threetreesttcvgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	gammavec(1) = minghval
	if(gammavec(1) > gamma) then
		prunenodenummattest(:,:) = nodenummattest(:,:)
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	allocate(nodenummatnew(traindatasize,maxdepth),nodenummatnewsub(traindatasize,maxdepth))
	allocate(nodenummatnewtest(testdatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
	call threetreesttcvgpruntreemat(nodenummat,maxdepth,traindatasize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	call threetreesttcvgpruntreemattest(nodenummattest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
	deallocate(nodenummatnewsub,nodenummatnewsubtest)
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesttcvgterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			prunenodenummattest(:,:) = 0d0
			prunenodenummattest(:,1) = 1d0
			prunenodenummat(:,:) = 0d0
			prunenodenummat(:,1) = 1d0
			exit
		endif
		call threetreesttcvgweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		gammavec(prunloop) = minghval
		if(gammavec(prunloop-1) < gamma .and. gammavec(prunloop) > gamma) then
			prunenodenummattest(:,:) = nodenummatnewtest(:,:)
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
		allocate(nodenummatnewsub(traindatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
		call threetreesttcvgpruntreemat(nodenummatnew,maxdepth,traindatasize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		call threetreesttcvgpruntreemattest(nodenummatnewtest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub,nodenummatnewsubtest)
	enddo
5000 continue
end subroutine threetreesttcvgammatreepruning
subroutine threetreesttcvgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesttcvgterminalnodecount
subroutine threetreesttcvgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesttcvgweaknode
subroutine threetreesttcvgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesttcvgpruntreemat
subroutine threetreesttcvgpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesttcvgpruntreemattest
subroutine threetreesttcvbesttreepruning(traindatasize,testdatasize,maxdepth,nodenummat,nodenummattest,allfval,&
levelcount,colnum,traindata,testdata,allgammaval,gammacv)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,levelcount,traindatasize,colnum,testdatasize
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	double precision, intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	double precision, intent(in) :: allfval((2**maxdepth)-1),allgammaval((2**(maxdepth-1))-1)
	double precision, intent(out) :: gammacv((2**(maxdepth-1))-1)
	double precision allgammavaltrain((2**(maxdepth-1))-1),losspredsumvec((2**(maxdepth-1))-1)
	double precision allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	double precision losspredsum,minghval
	integer cvprunloop,minghnum,allnodenum,nottnodeval,i,j,k
	integer nottnodevec((2**maxdepth)-1),ncountval((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:),nodenummatnewtest(:,:),nodenummatnewsubtest(:,:)
	allgammavaltrain(:) = 0d0
	gammacv(:) = 0d0
	losspredsumvec(:) = 0d0
	call threetreesttcvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
	nodenummattest,testdatasize,maxdepth,losspredsum)
	losspredsumvec(1) = losspredsum
	allocate(nodenummatnew(traindatasize,maxdepth),nodenummatnewtest(testdatasize,maxdepth))
	allfvalnew(:) = allfval(:)
	nodenummatnew(:,:) = nodenummat(:,:)
	nodenummatnewtest(:,:) = nodenummattest(:,:)
	do cvprunloop = 1,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesttcvbestterminalnodecount(nodenummatnew,traindatasize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			exit
		endif
		call threetreesttcvbestweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		allocate(nodenummatnewsub(traindatasize,maxdepth),nodenummatnewsubtest(testdatasize,maxdepth))
		call threetreesttcvbestpruntreemat(nodenummatnew,maxdepth,traindatasize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		call threetreesttcvbestpruntreemattest(nodenummatnewtest,maxdepth,testdatasize,minghnum,nodenummatnewsubtest)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		nodenummatnewtest(:,:) = nodenummatnewsubtest(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub,nodenummatnewsubtest)
		allgammavaltrain(cvprunloop+1) = minghval
		call threetreesttcvlosspredict(traindata,traindatasize,nodenummatnew,testdata,colnum,levelcount,&
		nodenummatnewtest,testdatasize,maxdepth,losspredsum)
		losspredsumvec(cvprunloop+1) = losspredsum
	enddo
	gammacv(1) = losspredsumvec(1)
	j = 2
	do i = 2,size(allgammaval)
		if(allgammaval(i) == 0d0) then
			exit
		endif
		if(allgammaval(i) <= allgammavaltrain(j)) then
			gammacv(i) = losspredsumvec(j-1)
		else
			do k = 1,size(allgammaval)
				if(allgammaval(i) > allgammavaltrain(j+k) .and. allgammavaltrain(j+k) > 0d0) then
					j = j + 1
				else
					exit
				endif
			enddo
			gammacv(i) = losspredsumvec(j)
			j = j + 1
		endif
	enddo
end subroutine threetreesttcvbesttreepruning
subroutine threetreesttcvlosspredict(traindata,traindatasize,nodenummat,testdata,colnum,levelcount,&
nodenummattest,testdatasize,maxdepth,losspredsum)
	IMPLICIT NONE
	integer, intent(in) :: traindatasize,testdatasize,maxdepth,colnum,levelcount
	integer, intent(in) :: nodenummat(traindatasize,maxdepth),nodenummattest(testdatasize,maxdepth)
	double precision, intent(in) :: traindata(traindatasize,colnum),testdata(testdatasize,colnum)
	double precision, intent(out) :: losspredsum
	double precision, allocatable :: timepred(:,:),losspred(:,:), timepredcou(:,:)
	integer i,j,k,l
	allocate(timepred(((2**maxdepth)-1),levelcount),losspred(((2**maxdepth)-1),levelcount))
	allocate(timepredcou(((2**maxdepth)-1),levelcount))
	timepred(:,:) = 0d0
	losspred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize
			if(sum(nodenummat(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(nodenummat(j,maxdepth) > 0) then
					timepred(nodenummat(j,maxdepth),int(traindata(j,3))) = timepred(nodenummat(j,maxdepth),int(traindata(j,3))) + traindata(j,1)
					timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) = timepredcou(nodenummat(j,maxdepth),int(traindata(j,3))) + 1d0
				endif
			elseif(nodenummat(j,i) > 0 .and. nodenummat(j,i+1) == 0) then
				timepred(nodenummat(j,i),int(traindata(j,3))) = timepred(nodenummat(j,i),int(traindata(j,3))) + traindata(j,1)
				timepredcou(nodenummat(j,i),int(traindata(j,3))) = timepredcou(nodenummat(j,i),int(traindata(j,3))) + 1d0
			endif
		enddo
	enddo
3010 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j=1,maxdepth
				if(2**(j-1) <= i .and. i < 2**j) then
					k = j
					exit
				endif
			enddo
			do l = 1,testdatasize
				if(nodenummattest(l,k) == i) then
					losspred(i,int(testdata(l,3))) = losspred(i,int(testdata(l,3))) + ((testdata(l,1) - timepred(i,int(testdata(l,3))))**2)
				endif
			enddo
		endif
	enddo
	losspredsum = sum(losspred)
	deallocate(timepred,losspred,timepredcou)
end subroutine threetreesttcvlosspredict
subroutine threetreesttcvbestterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesttcvbestterminalnodecount
subroutine threetreesttcvbestweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesttcvbestweaknode
subroutine threetreesttcvbestpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesttcvbestpruntreemat
subroutine threetreesttcvbestpruntreemattest(nodenummat,maxdepth,msize,minghnum,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	integer i,j,indcol
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesttcvbestpruntreemattest
subroutine threetreesttbootpredict(cvloop,traindata1,traindata2,traindata3,traindatasize1,traindatasize2,traindatasize3,&
nodenummat1,nodenummat2,nodenummat3,testdata1,testdata2,testdata3,testdataall,testdatasize1,testdatasize2,&
testdatasize3,testdataallsize,&
colnum,levelcount,nodenummattest1,nodenummattest2,nodenummattest3,maxdepth,&
r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub)
	IMPLICIT NONE
	integer,intent(in) :: colnum,levelcount,maxdepth,cvloop,traindatasize1,traindatasize2,traindatasize3
	integer,intent(in) :: testdatasize1,testdatasize2,testdatasize3,testdataallsize
	integer,intent(in) :: nodenummat1(traindatasize1,maxdepth),nodenummat2(traindatasize2,maxdepth),&
	nodenummat3(traindatasize3,maxdepth)
	integer,intent(in) :: nodenummattest1(testdataallsize,maxdepth),nodenummattest2(testdataallsize,maxdepth),&
	nodenummattest3(testdataallsize,maxdepth)
	double precision,intent(in) :: traindata1(traindatasize1,colnum),traindata2(traindatasize2,colnum),&
	traindata3(traindatasize3,colnum)
	double precision,intent(in) :: testdata1(testdatasize1,colnum),testdata2(testdatasize2,colnum),&
	testdata3(testdatasize3,colnum)
	double precision,intent(in) :: testdataall(testdataallsize,colnum)
	double precision,intent(out) :: r2cvval1sub,r2cvval2sub,r2cvval3sub,r2cvvalthreesub
	double precision bootpredictsub1(testdatasize1,5),bootpredictsub2(testdatasize2,5),bootpredictsub3(testdatasize3,5)
	double precision, allocatable :: timepred(:,:),timepredcou(:,:),predictvec(:),r2cvks0(:)
	integer i,j
	double precision ymean,r2cvbunsi,r2cvbunbo,r2cvks1,r2cvks2
	bootpredictsub1(:,1) = dble(cvloop)
	bootpredictsub1(:,2) = testdata1(:,1)
	bootpredictsub2(:,1) = dble(cvloop)
	bootpredictsub2(:,2) = testdata2(:,1)
	bootpredictsub3(:,1) = dble(cvloop)
	bootpredictsub3(:,2) = testdata3(:,1)
	allocate(timepred(((2**maxdepth)-1),levelcount),timepredcou(((2**maxdepth)-1),levelcount),predictvec(testdataallsize))
	timepred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize1
			if(sum(nodenummat1(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(nodenummat1(j,maxdepth) > 0) then
					timepred(nodenummat1(j,maxdepth),int(traindata1(j,3))) = &
					timepred(nodenummat1(j,maxdepth),int(traindata1(j,3))) + traindata1(j,1)
					timepredcou(nodenummat1(j,maxdepth),int(traindata1(j,3))) = &
					timepredcou(nodenummat1(j,maxdepth),int(traindata1(j,3))) + 1d0
				endif
				cycle
			endif
			if(nodenummat1(j,i) > 0 .and. nodenummat1(j,i+1) == 0) then
				timepred(nodenummat1(j,i),int(traindata1(j,3))) = &
				timepred(nodenummat1(j,i),int(traindata1(j,3))) + traindata1(j,1)
				timepredcou(nodenummat1(j,i),int(traindata1(j,3))) = &
				timepredcou(nodenummat1(j,i),int(traindata1(j,3))) + 1d0
			endif
		enddo
	enddo
3010 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,maxdepth
		do j = 1,testdataallsize
			if(sum(nodenummattest1(:,i)) == 0) then
				goto 3020
			endif
			if(i == maxdepth) then
				if(nodenummattest1(j,maxdepth) > 0) then
					predictvec(j) = timepred(nodenummattest1(j,maxdepth),int(testdataall(j,3)))
				endif
				cycle
			endif
			if(nodenummattest1(j,i) > 0 .and. nodenummattest1(j,i+1) == 0) then
				predictvec(j) = timepred(nodenummattest1(j,i),int(testdataall(j,3)))
			endif
		enddo
	enddo
3020 continue
	bootpredictsub1(:,3) = predictvec(1:testdatasize1)
	bootpredictsub2(:,3) = predictvec((testdatasize1+1):(testdatasize1+testdatasize2))
	bootpredictsub3(:,3) = predictvec((testdatasize1+testdatasize2+1):testdataallsize)
	deallocate(timepred,timepredcou,predictvec)
	allocate(timepred(((2**maxdepth)-1),levelcount),timepredcou(((2**maxdepth)-1),levelcount),predictvec(testdataallsize))
	timepred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize2
			if(sum(nodenummat2(:,i)) == 0) then
				goto 3030
			endif
			if(i == maxdepth) then
				if(nodenummat2(j,maxdepth) > 0) then
					timepred(nodenummat2(j,maxdepth),int(traindata2(j,3))) = &
					timepred(nodenummat2(j,maxdepth),int(traindata2(j,3))) + traindata2(j,1)
					timepredcou(nodenummat2(j,maxdepth),int(traindata2(j,3))) = &
					timepredcou(nodenummat2(j,maxdepth),int(traindata2(j,3))) + 1d0
				endif
				cycle
			endif
			if(nodenummat2(j,i) > 0 .and. nodenummat2(j,i+1) == 0) then
				timepred(nodenummat2(j,i),int(traindata2(j,3))) = &
				timepred(nodenummat2(j,i),int(traindata2(j,3))) + traindata2(j,1)
				timepredcou(nodenummat2(j,i),int(traindata2(j,3))) = &
				timepredcou(nodenummat2(j,i),int(traindata2(j,3))) + 1d0
			endif
		enddo
	enddo
3030 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,maxdepth
		do j = 1,testdataallsize
			if(sum(nodenummattest2(:,i)) == 0) then
				goto 3040
			endif
			if(i == maxdepth) then
				if(nodenummattest2(j,maxdepth) > 0) then
					predictvec(j) = timepred(nodenummattest2(j,maxdepth),int(testdataall(j,3)))
				endif
				cycle
			endif
			if(nodenummattest2(j,i) > 0 .and. nodenummattest2(j,i+1) == 0) then
				predictvec(j) = timepred(nodenummattest2(j,i),int(testdataall(j,3)))
			endif
		enddo
	enddo
3040 continue
	bootpredictsub1(:,4) = predictvec(1:testdatasize1)
	bootpredictsub2(:,4) = predictvec((testdatasize1+1):(testdatasize1+testdatasize2))
	bootpredictsub3(:,4) = predictvec((testdatasize1+testdatasize2+1):testdataallsize)
	deallocate(timepred,timepredcou,predictvec)
	allocate(timepred(((2**maxdepth)-1),levelcount),timepredcou(((2**maxdepth)-1),levelcount),predictvec(testdataallsize))
	timepred(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,traindatasize3
			if(sum(nodenummat3(:,i)) == 0) then
				goto 3050
			endif
			if(i == maxdepth) then
				if(nodenummat3(j,maxdepth) > 0) then
					timepred(nodenummat3(j,maxdepth),int(traindata3(j,3))) = &
					timepred(nodenummat3(j,maxdepth),int(traindata3(j,3))) + traindata3(j,1)
					timepredcou(nodenummat3(j,maxdepth),int(traindata3(j,3))) = &
					timepredcou(nodenummat3(j,maxdepth),int(traindata3(j,3))) + 1d0
				endif
				cycle
			endif
			if(nodenummat3(j,i) > 0 .and. nodenummat3(j,i+1) == 0) then
				timepred(nodenummat3(j,i),int(traindata3(j,3))) = &
				timepred(nodenummat3(j,i),int(traindata3(j,3))) + traindata3(j,1)
				timepredcou(nodenummat3(j,i),int(traindata3(j,3))) = &
				timepredcou(nodenummat3(j,i),int(traindata3(j,3))) + 1d0
			endif
		enddo
	enddo
3050 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepred(i,:))) > 0d0) then
			do j = 1,levelcount
				timepred(i,j) = timepred(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,maxdepth
		do j = 1,testdataallsize
			if(sum(nodenummattest3(:,i)) == 0) then
				goto 3060
			endif
			if(i == maxdepth) then
				if(nodenummattest3(j,maxdepth) > 0) then
					predictvec(j) = timepred(nodenummattest3(j,maxdepth),int(testdataall(j,3)))
				endif
				cycle
			endif
			if(nodenummattest3(j,i) > 0 .and. nodenummattest3(j,i+1) == 0) then
				predictvec(j) = timepred(nodenummattest3(j,i),int(testdataall(j,3)))
			endif
		enddo
	enddo
3060 continue
	bootpredictsub1(:,5) = predictvec(1:testdatasize1)
	bootpredictsub2(:,5) = predictvec((testdatasize1+1):(testdatasize1+testdatasize2))
	bootpredictsub3(:,5) = predictvec((testdatasize1+testdatasize2+1):testdataallsize)
	r2cvks1 = 0d0
	r2cvks2 = 0d0
	ymean = sum(bootpredictsub1(:,2))/testdatasize1
	do i = 1,testdatasize1
		r2cvks1 = r2cvks1 + (bootpredictsub1(i,2)-bootpredictsub1(i,3)) * (bootpredictsub1(i,2)-bootpredictsub1(i,3))
		r2cvks2 = r2cvks2 + (bootpredictsub1(i,2)-ymean) * (bootpredictsub1(i,2)-ymean)
	enddo
	r2cvbunsi = r2cvks1
	r2cvbunbo = r2cvks2
	r2cvval1sub = 1d0-(r2cvbunsi/r2cvbunbo)
	r2cvks1 = 0d0
	r2cvks2 = 0d0
	ymean = sum(bootpredictsub2(:,2))/testdatasize2
	do i = 1,testdatasize2
		r2cvks1 = r2cvks1 + (bootpredictsub2(i,2)-bootpredictsub2(i,4)) * (bootpredictsub2(i,2)-bootpredictsub2(i,4))
		r2cvks2 = r2cvks2 + (bootpredictsub2(i,2)-ymean) * (bootpredictsub2(i,2)-ymean)
	enddo
	r2cvbunsi = r2cvks1
	r2cvbunbo = r2cvks2
	r2cvval2sub = 1d0-(r2cvbunsi/r2cvbunbo)
	r2cvks1 = 0d0
	r2cvks2 = 0d0
	ymean = sum(bootpredictsub3(:,2))/testdatasize3
	do i = 1,testdatasize3
		r2cvks1 = r2cvks1 + (bootpredictsub3(i,2)-bootpredictsub3(i,5)) * (bootpredictsub3(i,2)-bootpredictsub3(i,5))
		r2cvks2 = r2cvks2 + (bootpredictsub3(i,2)-ymean) * (bootpredictsub3(i,2)-ymean)
	enddo
	r2cvbunsi = r2cvks1
	r2cvbunbo = r2cvks2
	r2cvval3sub = 1d0-(r2cvbunsi/r2cvbunbo)
	r2cvks1 = 0d0
	r2cvks2 = 0d0
	ymean = (sum(bootpredictsub1(:,2))+sum(bootpredictsub2(:,2))+sum(bootpredictsub3(:,2)))/testdataallsize
	allocate(r2cvks0(testdatasize1))
	r2cvks0(:) = (bootpredictsub1(:,3)+bootpredictsub1(:,4)+bootpredictsub1(:,5))/3d0
	do i = 1,testdatasize1
		r2cvks1 = r2cvks1 + (bootpredictsub1(i,2)-r2cvks0(i)) * (bootpredictsub1(i,2)-r2cvks0(i))
		r2cvks2 = r2cvks2 + (bootpredictsub1(i,2)-ymean) * (bootpredictsub1(i,2)-ymean)
	enddo
	deallocate(r2cvks0)
	allocate(r2cvks0(testdatasize2))
	r2cvks0(:) = (bootpredictsub2(:,3)+bootpredictsub2(:,4)+bootpredictsub2(:,5))/3d0
	do i = 1,testdatasize2
		r2cvks1 = r2cvks1 + (bootpredictsub2(i,2)-r2cvks0(i)) * (bootpredictsub2(i,2)-r2cvks0(i))
		r2cvks2 = r2cvks2 + (bootpredictsub2(i,2)-ymean) * (bootpredictsub2(i,2)-ymean)
	enddo
	deallocate(r2cvks0)
	allocate(r2cvks0(testdatasize3))
	r2cvks0(:) = (bootpredictsub3(:,3)+bootpredictsub3(:,4)+bootpredictsub3(:,5))/3d0
	do i = 1,testdatasize3
		r2cvks1 = r2cvks1 + (bootpredictsub3(i,2)-r2cvks0(i)) * (bootpredictsub3(i,2)-r2cvks0(i))
		r2cvks2 = r2cvks2 + (bootpredictsub3(i,2)-ymean) * (bootpredictsub3(i,2)-ymean)
	enddo
	deallocate(r2cvks0)
	r2cvbunsi = r2cvks1
	r2cvbunbo = r2cvks2
	r2cvvalthreesub = 1d0-(r2cvbunsi/r2cvbunbo)
	deallocate(timepred,timepredcou,predictvec)
end subroutine threetreesttbootpredict
subroutine threetreesgammatreepruning(prunind,msize,bestgammaval,cv,maxdepth,nodenummat,allfval,prunenodenummat)
	implicit none
	integer,intent(in) :: msize,maxdepth,prunind,cv
	integer,intent(in) :: nodenummat(msize,maxdepth)
	double precision,intent(in) :: bestgammaval,allfval((2**maxdepth)-1)
	integer,intent(out) :: prunenodenummat(msize,maxdepth)
	double precision minghval
	double precision gammavec((2**(maxdepth-1))-1),allfvalnew((2**maxdepth)-1),allfvalnewsub((2**maxdepth)-1)
	integer nottnodeval,allnodenum,minghnum,prunloop
	integer ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	integer, allocatable :: nodenummatnew(:,:),nodenummatnewsub(:,:)
	if(bestgammaval <= 0d0 .or. prunind==1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	gammavec(:) = 0d0
	call threetreesgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	call threetreesgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	gammavec(1) = minghval
	if(gammavec(1) > bestgammaval .and. cv == -1) then
		prunenodenummat(:,:) = nodenummat(:,:)
		goto 5000
	endif
	allocate(nodenummatnew(msize,maxdepth),nodenummatnewsub(msize,maxdepth))
	call threetreesgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnewsub)
	nodenummatnew(:,:) = nodenummatnewsub(:,:)
	deallocate(nodenummatnewsub)
	if(bestgammaval == minghval .and. cv == 1) then
		prunenodenummat(:,:) = nodenummatnew(:,:)
		goto 5000
	endif
	do prunloop = 2,((2**(maxdepth-1))-2)
		allfvalnewsub(:) = 0d0
		call threetreesgterminalnodecount(nodenummatnew,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
		if(allnodenum == 1) then
			prunenodenummat(:,:) = 0d0
			prunenodenummat(:,1) = 1d0
			exit
		endif
		call threetreesgweaknode(maxdepth,nottnodeval,ncountval,allfvalnew,nottnodevec,minghnum,minghval)
		gammavec(prunloop) = minghval
		if(gammavec(prunloop-1) < bestgammaval .and. gammavec(prunloop) > bestgammaval .and. cv == -1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
		allocate(nodenummatnewsub(msize,maxdepth))
		call threetreesgpruntreemat(nodenummatnew,maxdepth,msize,minghnum,allfvalnew,allfvalnewsub,nodenummatnewsub)
		nodenummatnew(:,:) = nodenummatnewsub(:,:)
		allfvalnew(:) = allfvalnewsub(:)
		deallocate(nodenummatnewsub)
		if(bestgammaval == minghval .and. cv == 1) then
			prunenodenummat(:,:) = nodenummatnew(:,:)
			goto 5000
		endif
	enddo
5000 continue
end subroutine threetreesgammatreepruning
subroutine threetreesgterminalnodecount(nodenummat,msize,maxdepth,nottnodeval,ncountval,nottnodevec,allnodenum)
	IMPLICIT NONE
	integer, intent(in) :: msize,maxdepth
	integer,intent(in) :: nodenummat(msize,maxdepth)
	integer, intent(out) :: nottnodeval, ncountval((2**maxdepth)-1), nottnodevec((2**maxdepth)-1), allnodenum
	integer tncountval((2**maxdepth)-1)
	integer i,j,tnodeval
	tncountval(:) = 0
	ncountval(:) = 0
	nottnodevec(:) = 0
	allnodenum = 0
	do i =1,msize
		do j = 1,maxdepth-1
			if(nodenummat(i,j+1) == 0) then
				tncountval(nodenummat(i,j)) = 1
				exit
			else
				ncountval(nodenummat(i,j)) = 1
				nottnodevec(nodenummat(i,j)) = nodenummat(i,j)
			endif
		enddo
	enddo
	do i = 1,msize
		if(nodenummat(i,maxdepth) > 0) then
			tncountval(nodenummat(i,maxdepth)) = 1
		endif
	enddo
	tnodeval = sum(tncountval)
	nottnodeval = sum(ncountval)
	allnodenum = tnodeval+nottnodeval
end subroutine threetreesgterminalnodecount
subroutine threetreesgweaknode(maxdepth,nottnodeval,ncountval,allfval,nottnodevec,minghnum,minghval)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,nottnodeval, ncountval((2**maxdepth)-1),nottnodevec((2**maxdepth)-1)
	double precision allfval((2**maxdepth)-1), testsum, testsumall((2**maxdepth)-1), ghval((2**maxdepth)-1)
	integer rootnodenum, prunloop,i,j, ntcount((2**maxdepth)-1)
	integer, intent(out) :: minghnum
	double precision, intent(out) :: minghval
	ghval(:) = 0d0
	testsumall(:) = 0d0
	ntcount(:) = 0
	do prunloop = 1,((2**maxdepth)-1)
		if(nottnodevec(prunloop) > 0) then
			rootnodenum = nottnodevec(prunloop)
			ntcount(rootnodenum) = 1
			testsum = allfval(rootnodenum)
			do i = 1,(maxdepth-2)
				if(((2**i)*rootnodenum) > ((2**maxdepth)-1)) then
					exit
				endif
				do j = 1,(2**i)
					testsum = testsum + allfval(((2**i)*rootnodenum)+j-1)
					if(allfval(((2**i)*rootnodenum)+j-1) > 0d0) then
						ntcount(rootnodenum) = ntcount(rootnodenum) + 1
					endif
				enddo
			enddo
			testsumall(rootnodenum) = testsum
		endif
	enddo
	j = 1
	do i = 1,((2**maxdepth)-1)
		if(ntcount(i) > 0) then
			ghval(i) = testsumall(i) / dble(ntcount(i))
			if(j == 1) then
				minghval = ghval(i)
				minghnum = i
				j = j + 1
			endif
			if(minghval > ghval(i)) then
				minghval = ghval(i)
				minghnum = i
			endif
		endif
	enddo
end subroutine threetreesgweaknode
subroutine threetreesgpruntreemat(nodenummat,maxdepth,msize,minghnum,allfval,allfvalnew,nodenummatnew)
	IMPLICIT NONE
	integer, intent(in) :: maxdepth,msize,minghnum
	integer, intent(in) :: nodenummat(msize,maxdepth)
	double precision, intent(in) :: allfval((2**maxdepth)-1)
	integer, intent(out) :: nodenummatnew(msize,maxdepth)
	double precision, intent(out) :: allfvalnew((2**maxdepth)-1)
	integer i,j,indcol
	do i = 1,((2**maxdepth)-1)
		allfvalnew(i) = allfval(i)
	enddo
	allfvalnew(minghnum) = 0d0
	do i = 1,(maxdepth-1)
		if(minghnum < (2**i)) then
			indcol = i
			exit
		endif
	enddo
	do i = 1,msize
		nodenummatnew(i,:) = nodenummat(i,:)
		if(nodenummatnew(i,indcol) == minghnum) then
			do j = (indcol+1),maxdepth
				if(nodenummatnew(i,j) > 0) then
					allfvalnew(nodenummatnew(i,j)) = 0d0
				endif
				nodenummatnew(i,j) = 0
			enddo
		endif
	enddo
end subroutine threetreesgpruntreemat
subroutine threetreestreepredict(msize,levelcount,maxdepth,colnum,prunenodenummat,XYDATA,predvec,datatnnodenum)
	implicit none
	integer, intent(in) :: msize,levelcount,maxdepth,colnum
	integer, intent(in) :: prunenodenummat(msize,maxdepth)
	double precision, intent(in) :: XYDATA(Msize,colnum)
	integer, intent(out) :: datatnnodenum(msize)
	double precision, intent(out) :: predvec(msize)
	double precision, allocatable :: timepredsum(:,:),timepredcou(:,:)
	double precision tnodepredmat((2**maxdepth)-1,levelcount)
	integer i,j
	allocate(timepredsum(((2**maxdepth)-1),levelcount),timepredcou(((2**maxdepth)-1),levelcount))
	timepredsum(:,:) = 0d0
	timepredcou(:,:) = 0d0
	do i = 1,maxdepth
		do j = 1,msize
			if(sum(prunenodenummat(:,i)) == 0) then
				goto 3010
			endif
			if(i == maxdepth) then
				if(prunenodenummat(j,maxdepth) > 0) then
					timepredsum(prunenodenummat(j,maxdepth),int(XYDATA(j,3))) = &
					timepredsum(prunenodenummat(j,maxdepth),int(XYDATA(j,3))) + XYDATA(j,1)
					timepredcou(prunenodenummat(j,maxdepth),int(XYDATA(j,3))) = &
					timepredcou(prunenodenummat(j,maxdepth),int(XYDATA(j,3))) + 1d0
					datatnnodenum(j) = prunenodenummat(j,maxdepth)
				endif
				cycle
			elseif(prunenodenummat(j,i) > 0 .and. prunenodenummat(j,i+1) == 0) then
				timepredsum(prunenodenummat(j,i),int(XYDATA(j,3))) = &
				timepredsum(prunenodenummat(j,i),int(XYDATA(j,3))) + XYDATA(j,1)
				timepredcou(prunenodenummat(j,i),int(XYDATA(j,3))) = &
				timepredcou(prunenodenummat(j,i),int(XYDATA(j,3))) + 1d0
				datatnnodenum(j) = prunenodenummat(j,i)
			endif
		enddo
	enddo
3010 continue
	do i = 1,((2**maxdepth)-1)
		if(abs(sum(timepredsum(i,:))) > 0d0) then
			do j = 1,levelcount
				tnodepredmat(i,j) = timepredsum(i,j)/timepredcou(i,j)
			enddo
		endif
	enddo
	do i = 1,msize
		predvec(i) = tnodepredmat(datatnnodenum(i),int(xydata(i,3)))
	enddo
end subroutine threetreestreepredict
subroutine threetreesnodedata(xydata,msize,colnum,nodenum,hierarchy,nodenummat,nodesize,xynodedata)
	IMPLICIT NONE
	integer, intent(in) :: msize,colnum,nodenum,hierarchy,nodesize
	double precision, intent(in) :: xydata(msize,colnum)
	integer, intent(in) :: nodenummat(msize,11)
	double precision, intent(out) :: xynodedata(nodesize,colnum)
	integer i,j
	j = 1
	do i = 1,msize
		if(nodenummat(i,hierarchy) == nodenum) then
			xynodedata(j,:) = xydata(i,:)
			j = j + 1
		endif
	enddo
end subroutine threetreesnodedata
subroutine threetreessplitvec(nodedatanum,nodedatasize,colnum,msize,maxdepth,DATATYPE,prunnodenummat,&
ind1,ind2,splitvecsize,splitnumber,splitvector)
	IMPLICIT NONE
	integer, intent(in) :: nodedatasize,colnum,maxdepth,ind1,ind2,splitvecsize,msize
	integer, intent(in) :: datatype(colnum-3)
	double precision, intent(in) :: nodedatanum(nodedatasize,colnum)
	integer, intent(in) :: prunnodenummat(msize,maxdepth)
	integer, intent(out) :: splitvector(splitvecsize)
	double precision, intent(out) :: splitnumber(splitvecsize)
	integer i,j,hierarchy,nodesize,facsum,count_0,count_1,idx,splitnum,countvec
	double precision datasample(nodedatasize)
	integer, allocatable :: splitindmat(:,:)
	datasample = nodedatanum(:,ind1)
	if(datatype(ind1-3) == 1) then
		splitnum = splitvecsize - 1
	elseif(datatype(ind1-3) == 2) then
		splitnum = (2 ** (splitvecsize-1)) - 1
	endif
	call threetreesspdataval(nodedatanum(:,ind1),nodedatasize,splitnumber,splitvecsize)
	allocate(splitindmat(splitnum,splitvecsize))
	if(datatype(ind1-3) == 1) then
		do i = 1,splitnum
			do j = 1,splitvecsize
				if(i >= j) then
					splitindmat(i,j) = 0
				else
					splitindmat(i,j) = 1
				endif
			enddo
		enddo
	elseif(datatype(ind1-3) == 2) then
	    idx = 1
		do i = 0, 2**(splitvecsize-1) - 1
			count_0 = 1
			count_1 = 0
			splitindmat(idx, 1) = 0
			do j = 0, splitvecsize - 2
				if (iand(i, 2**j) /= 0) then
					splitindmat(idx, j+2) = 1
					count_1 = count_1 + 1
				else
					splitindmat(idx, j+2) = 0
					count_0 = count_0 + 1
				end if
			end do
			if (count_0 > 0 .and. count_1 > 0) then
				idx = idx + 1
			end if
	    end do
	endif
	splitvector = splitindmat(ind2,:)
end subroutine threetreessplitvec
subroutine threetreesspdataval(datavec,msize,facval,facsize)
	IMPLICIT NONE
	integer,intent(in) :: msize, facsize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	double precision, intent(out) :: facval(facsize)
	integer count, i, j, k
	datavecsub(:) = datavec(:)
	call threetreesspdatasort(datavecsub,1,msize)
	facval(1) = datavecsub(1)
	k = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			k = k + 1
			facval(k) = datavecsub(j)
		endif
	enddo
end subroutine threetreesspdataval
subroutine threetreesspdatasum(datavec,msize,facsum)
	IMPLICIT NONE
	integer,intent(in) :: msize
	double precision,intent(in) :: datavec(msize)
	double precision datavecsub(msize)
	integer, intent(out) :: facsum
	integer count, j, i
	datavecsub(:) = datavec(:)
	call threetreesspdatasort(datavecsub,1,msize)
	count = 1
	do j = 2,msize
		if(abs(datavecsub(j) - datavecsub(j-1)) > 0d0) then
			count = count + 1
		endif
	enddo
	facsum = count
end subroutine threetreesspdatasum
recursive subroutine threetreesspdatasort(datavec,start,msize)
	implicit none
	integer,intent(in)::start,msize
	double precision,intent(inout)::datavec(msize)
	double precision x,t
	integer i,j
	x = datavec((start+msize)/2)
	i = start
	j = msize
	do
		do while (datavec(i) < x)
			i=i+1
		end do
		do while (x < datavec(j))
			j=j-1
		end do
		if (i >= j) exit
		t = datavec(i)
		datavec(i) = datavec(j)
		datavec(j) = t
		i=i+1
		j=j-1
	end do
	if (start < i-1) then
		call threetreesspdatasort(datavec, start, i-1)
	endif
	if (j+1 < msize) then
		call threetreesspdatasort(datavec, j+1, msize)
	endif
	return
end subroutine threetreesspdatasort
