R/PopulationSampler.R

#' @include SampleLogs.R
#' @include ChainSamplerImpl.R
#' @include JumpProposer.R
#' @include DEJumpProposer.R
#' @include AcceptanceTracker.R


#' @export
newPopulationSampler <- function(
        ### create a new PopulationSampler based on given blockSpecifications
        blockSpecifications ##<< list of blockSpecifications (see \code{\link{blockSpec}})
        ,thetaPrior		##<< numeric vector (nParm) of point estimate of the mean
        ,covarTheta 	##<< numeric matrix (nParm x nParm) the covariance of parameters.
        ,...            ##<< other arguments to \code{\link{createSampleLogsWithInitialPopulation}}, e.g. \code{Zinit}, \code{nChainGroupsInPopulation}
        ## such as \code{nPopulation} and \code{nChainInPopulation}
        ,intermediateSpecifications=list()       ##<< list of intermediateSpecifications (see \code{\link{intermediateSpec}})
        ,chainSamplerTemplate=new("ChainSamplerImpl")   ##<< subClass of ChainSampler that will be initialized and used
        ,className="PopulationSampler"
        ,subSpace=new("SubSpace")                       ##<< constraint of sampling range
        ,sampleLogs     ##<< alternative to specify initial population, instead of thetaPrior and covarTheta
){
    namesTheta <- if( !missing(sampleLogs) ){ getParameterNames(sampleLogs) } else
                  if( hasArg("Zinit") ){ rownames(list(...)$Zinit) } else
                  if( !missing(thetaPrior) ){ names(thetaPrior) } else
                  stopDemac("need specify initial population either by Zinit, sampleLogs, or (thetaPrior, covarTheta)")
    blockUpdaters <- newBlockUpdaters(blockSpecifications, intermediateSpecifications, namesTheta)
    chainSampler <- initializeBlockUpdaters(chainSamplerTemplate, blockUpdaters)
    sampler <- new(className, chainSampler=chainSampler)
    sampleLogs(sampler) <-if( missing(sampleLogs) ){
        initialLogs <- createSampleLogsWithInitialPopulation(sampler
                ,thetaPrior=thetaPrior
                ,covarTheta=covarTheta
                ,subSpace=subSpace
                ,...
        ) 
        initialLogs
    } else {
        sampleLogs
    }
    subSpacePopulations(sampler) <- rep(list(subSpace), getNPopulation(getSampleLogs(sampler))) 
    sampler            
}


setOldClass("cluster")
setClass("SOCKcluster", contains = "cluster")
setOldClass("SOCKcluster", S4Class = "SOCKcluster")

#' @export
setClass("PopulationSampler",
        representation(
                chainStates = "list"
                ,sampleLogs = "SampleLogs"
                ,chainSampler = "ChainSampler"
                ,jumpProposer = "JumpProposer"
                ,acceptanceTracker = "AcceptanceTracker"
                ,progressOutput = "character"
                ,subSpacePopulations = "list"	                    
                ,stepTemperaturesPopulations = "list"	 
                ,cluster = "cluster"
                ,nIntervalPerRange = "integer"	        ##<< number of thinning intervals before regenerating jumps
                ,nSampleBeforeSampling = "integer"	    # integer vector (nPopulation): number of samples in sampleLog, before sampling 
                ,nSampleBatchPopulations = "integer"	            # integer vector (nPopulation): number of samples sample and append to sampleLog
                ,isBurnin = "logical"	        ##<< if current sampling proceeds in burnin mode
                ,nRepresentativeRows= "integer"	        ##<< number of independent rows necessary to represent parameter space with current number of chainsInPopulation
        )
        ,prototype( 
                chainSampler = new("ChainSamplerImpl")
                , jumpProposer = new("DEJumpProposer")  
                , acceptanceTracker = new("AcceptanceTracker")
                , sampleLogs = new("SampleLogs")
                , cluster=structure(list(),class=c("SOCKcluster","cluster"))
                , progressOutput="."
                , nIntervalPerRange=2L
                , isBurnin=TRUE
                , nRepresentativeRows=NA_integer_
        )
)


if(!exists("createSampleLogsWithInitialPopulation")) setGeneric("createSampleLogsWithInitialPopulation", function(object,...) standardGeneric("createSampleLogsWithInitialPopulation"))
setMethod("createSampleLogsWithInitialPopulation", signature="PopulationSampler", 
        function( object
                ### Generate an initial population of states for \code{\link{twDEMCBlockInt}}.
                ,thetaPrior		##<< numeric vector (nParm) of point estimate of the mean
                ,covarTheta 	##<< numeric matrix (nParm x nParm) the covariance of parameters.
                ##<< Alternatively, can be given as vector (nParm) of the diagonal, i.e. variances, if all dimensions are independent
                , nPopulation=2L
                , nChainInPopulation=3L
                , nChainGroupsInPopulation=1L
                ,m0= computeNRepresentativeRows(length(thetaPrior),nChainInPopulation)/(m0FiniteFac)
                ### number of initial states for each chain
                ,m0FiniteFac=1	##<< use a factor smaller than 1 to increase default m0 to account for only a portion of proposal results in finite densities
                ,doIncludePrior=TRUE
                ### If TRUE, then set last sample of chain 1 to the prior estimate, 
                ### which might be already a kind of best estimates by an optimization.
                ,subSpace=new("SubSpace")                       ##<< constraint of sampling range
                ,Zinit          ##<< sample (nParm, nStep) as an alternative to (thetaPrior,covarTheta) to specify initial logs
        ){
            ##seealso<<  
            ## \code{\link{computeNRepresentativeRows}}
            #?rmvnorm #in package mvtnorm
            if( !missing(Zinit) ) thetaPrior <- Zinit[,1L]
            blockDimensions <- getBlockDimensions(object@chainSampler)
            if( getNBlock(blockDimensions)==0 ) stop("Need to setup chainSampler with blockSpecificiations before computing setting up sampleLog.")
            sampleDimensions <- initializeSampleDimensionsImpl(
                    new("SampleDimensionsImpl")
                    , blockDimensions = blockDimensions
                    , nSamplePopulations=rep(1L, nPopulation)
                    , nChainInPopulation=nChainInPopulation
                    , nChainGroupsInPopulation = nChainGroupsInPopulation
            )
            nChain <- getNChain(sampleDimensions) 	##<< number of chains to run
            nParameter <- getNParameter(sampleDimensions)
            parameterNames <- getParameterNames(sampleDimensions)
            if( length(thetaPrior) != nParameter )
                stop("Mismatch between length of prior and number of parameters in Sampler.")
            if( !length(names(thetaPrior)) ) names(thetaPrior) <- parameterNames 
            if( !all(names(thetaPrior) == parameterNames) )
                stop("Mismatch between parameternames in prior and in Sampler.")
            ZinitChains <- if( missing(Zinit) ) computeInitialPopulation(
                    thetaPrior, covarTheta
                    #, sampleDimensions=sampleDimensions
                    ,nChainInPopulation = getNChainInPopulation(sampleDimensions)
                    ,nPopulation = getNPopulation(sampleDimensions)
                    , m0=m0, m0FiniteFac=m0FiniteFac, doIncludePrior=doIncludePrior
                    , subSpace=subSpace
            ) else {
                # condense Zinit to m0 * nChain
                if( ncol(Zinit)  < (m0*nChain/2) ) stopDemac("too few initial samples")
                structure( Zinit[,sample.int(ncol(Zinit),m0*nChain,replace=TRUE)], dim=c(nParameter, m0, nChain), dimnames=list(parms=rownames(Zinit),NULL,NULL) )
            }
            # take the last row (or alternative samples with finite logDensity) and provide as x0 and logDensityComponents 0 
            resInitial <- .ensureFiniteLogDensityInInitialState(object, ZinitChains)
            sampleLogs <- do.call( .createInitialSampleLogs, c(list(object, sampleDimensions=sampleDimensions), resInitial) )
            ##value<< a SampleLogsObject with 1 sample and an initial population 
            sampleLogs
        })


#if(!exists(".computeInitialPopulation")) setGeneric(".computeInitialPopulation", function(object,...) standardGeneric(".computeInitialPopulation"))
#setMethod(".computeInitialPopulation", signature="PopulationSampler",
#' @export
computeInitialPopulation <-
        function( #object,
                ### Generate an initial population of states for \code{\link{twDEMCBlockInt}}.
                thetaPrior		##<< numeric vector (nParm) of point estimate of the mean
                ,covarTheta 	##<< numeric matrix (nParm x nParm) the covariance of parameters.
                ##<< Alternatively, can be given as vector (nParm) of the diagonal, i.e. variances, if all dimensions are independent
                ,nChainInPopulation = 1L   ##<< number of chains in population (defaults to nChain, i.e. one population)
                ,nPopulation = 1L       ##<< defaults to 1
                ,parameterNames = names(thetaPrior)
                ,m0= computeNRepresentativeRows(length(thetaPrior),nChainInPopulation)/(m0FiniteFac)
                ### number of initial states for each chain
                ,m0FiniteFac=1	##<< use a factor smaller than 1 to increase default m0 to account for only a portion of proposal results in finite densities
                ,doIncludePrior=TRUE
                ### If TRUE, then set last sample of chain 1 to the prior estimate, 
                ### which might be already a kind of best estimates by an optimization.
                ,subSpace=new("SubSpace")                       ##<< constraint of sampling range
        ){
                    ##<< scalar integer: number of chains, i.e. columns to generate
            nChain <- nPopulation * nChainInPopulation
            nParameter <- length(thetaPrior)
            Zinit <- if( nParameter==1L ){
                        abind( lapply( 1:nChain, function(i){ 
                                            samples <- rnorm( m0, mean=thetaPrior, sd=covarTheta)
                                            names(samples) <- parameterNames
                                            samples <- .letSubSpaceReflectBoundaries(subSpace, samples)
                                            matrix(samples, nrow=1, dimnames=list(parameterNames,NULL) ) })
                                , along=3 )
                    } else {
                        if( is.matrix(covarTheta))
                            abind( lapply( 1:nChain, function(i){ 
                                                samples <- rmvnorm( m0, mean=thetaPrior, sigma=covarTheta ) 
                                                colnames(samples) <- names(thetaPrior)
                                                samplesConstr <- .letSubSpaceReflectBoundariesMatrix(subSpace, samples)
                                                t(samplesConstr) 
                                            })
                                    , along=3 )
                        else
                            # independent dimensions, can sample each from rnorm
                            abind( lapply( 1:nChain, function(i){
                                                #iComp=1
                                                samples <- sapply( seq_along(thetaPrior), function(iComp){
                                                            rnorm(m0, mean=thetaPrior[iComp], sd=covarTheta[iComp])
                                                        })
                                                colnames(samples) <- names(thetaPrior)
                                                samplesConstr <- .letSubSpaceReflectBoundariesMatrix(subSpace, samples)
                                                t(samplesConstr)
                                            }), along=3 )
                    }
            # Set the last sample of chain 1 to the prior estimate, which might be already a kind of best estimates by an optimization.
            if( doIncludePrior )
                Zinit[,m0,1 ] <- .letSubSpaceReflectBoundaries(subSpace, thetaPrior)
            dimnames(Zinit) = list(parameterNames,NULL,NULL)
            Zinit
        }

if(!exists(".ensureFiniteLogDensityInInitialState")) setGeneric(".ensureFiniteLogDensityInInitialState", function(object,...) standardGeneric(".ensureFiniteLogDensityInInitialState"))
setMethod(".ensureFiniteLogDensityInInitialState", signature="PopulationSampler",
        function(object, Zinit){ 
            # compute logDensities of last state
            x0 <- adrop(Zinit[,ncol(Zinit), ,drop=FALSE],2)
            x0Chain <- x0[,1L]
            chainState <- computeChainState(object@chainSampler, x0Chain)   # invoke computation once outside alply for debugging
            logDensityComponents0 <- abind( alply(x0, 2, function(x0Chain){
                        chainState <- computeChainState(object@chainSampler, x0Chain)
                        getLogDensityComponents(chainState)
                    }), along=2)
            if( !any(is.finite(colSums(logDensityComponents0)))) stopDemac("All initial states yield non-finite logDensities. Check your logDensity functions.")
            if( getNLogDensityComponent(getBlockDimensions(getChainSampler(object))) != 0L ){
                #logDensityComponents0[1,1:3] <- -Inf
                iNonFinite <- which( !apply(logDensityComponents0,2, function(logDensityComponents0Chain){
                                    all(is.finite(logDensityComponents0Chain))}))
                if( length(iNonFinite) ){
                    # take n alternative samples from other rows and calculte logDensity
                    # then replace the non-Finite cases in x0
                    propNonfinite <- length(iNonFinite)/ncol(logDensityComponents0)
                    nAlternativeSamples <- ceiling(length(iNonFinite)*3/(1-propNonfinite))  
                    iSteps <- sample.int(ncol(Zinit)-1, nAlternativeSamples, replace=TRUE)
                    iChains <- sample.int( dim(Zinit)[3], nAlternativeSamples, replace=TRUE)
                    x0Alt <- abind( lapply(1:nAlternativeSamples, function(i){Zinit[,iSteps[i],iChains[i]]}), along=2)
                    logDensityComponents0Alt <- abind( alply(x0Alt, 2, function(x0Chain){
                                        chainState <- computeChainState(object@chainSampler, x0Chain)
                                        getLogDensityComponents(chainState)
                            }),along=2)
                    iFiniteAlt <- which( apply(logDensityComponents0Alt,2, function(logDensityComponents0Chain){
                                        all(is.finite(logDensityComponents0Chain))}))
                    if( length(iFiniteAlt) < length(iNonFinite) ){
                        #recover()
                        stop("could not get enough initial states with finite logDensity.")                        
                    } 
                    iFiniteAlt <- iFiniteAlt[1:length(iNonFinite)]
                    x0[,iNonFinite] <- x0Alt[,iFiniteAlt]
                    logDensityComponents0[,iNonFinite] <- logDensityComponents0Alt[,iFiniteAlt]
                }
            }
            ##value<< list with entries
            list(
                    initialPopulation=Zinit[,-ncol(Zinit), ,drop=FALSE]  ##<< array of parameters (nParameter, m0, nChain)
                    ,x0=x0                                               ##<< vector of parameters (nParameter)
                    ,logDensityComponents0=logDensityComponents0         ##<< logDensityComponent of x0
            )
        })

if(!exists(".createInitialSampleLogs")) setGeneric(".createInitialSampleLogs", function(object,...) standardGeneric(".createInitialSampleLogs"))
setMethod(".createInitialSampleLogs", signature="PopulationSampler", 
        function( object
                ### Generate an initial population of states for \code{\link{twDEMCBlockInt}}.
                ,sampleDimensions       
                ,initialPopulation
                ,x0
                ,logDensityComponents0
        ){
            sampleLogs <- object@sampleLogs     # template object
            sampleDimensions(sampleLogs) <- sampleDimensions
            initialPopulation(sampleLogs) <- initialPopulation
            sampleLogs <- setSampleRecord(sampleLogs,
                    iSample = 1L
                    ,parameters = x0
                    ,logDensityComponents = logDensityComponents0
            )
            sampleLogs            
        })

if(!exists("sampleLogs<-")) setGeneric("sampleLogs<-", function(object,value) standardGeneric("sampleLogs<-"))
# need to export, because of SannSampler inherits .adjustThinningToSpectralDensity from BatchSampler
#' @export
setReplaceMethod("sampleLogs", signature=c("PopulationSampler", "SampleLogs"), 
        function(object, value) {
            if( !(.isSampleLogsConsistentWithChainSampler(value, object@chainSampler)) ) 
                stop("Can only set sampleLogs that is consistent with ChainSampler.")
            sampleLogsOrig <- object@sampleLogs 
            object@sampleLogs <- value
            blockDimensions(object@sampleLogs) <- getBlockDimensions(object@chainSampler)
            hasChangedDimensions <-
                    getNParameter(value) != getNParameter(sampleLogsOrig) || 
                    any(getParameterNames(value) != getParameterNames(sampleLogsOrig)) ||
                    getNPopulation(value) != getNPopulation(sampleLogsOrig)                                         
            if( hasChangedDimensions ){
                if( getNParameter(sampleLogsOrig) )
                    warning("sampleLogs<-: replacing subSpacePopulations by empty objects because of changed dimensions")
                # changes sampleDimensions, need to reinitialized indexBounds
                # NULL objects for subspaces that should be set separately
                # setter takes care of initializing indexedBounds
                subSpacePopulations(object) <- rep(list(new("SubSpace")) 
                        , getNPopulation(getSampleDimensions(object)))
                object@nRepresentativeRows <- computeNRepresentativeRows(getNParameter(object@sampleLogs), getNChainInPopulation(object@sampleLogs))
                # temperatures and jumpProposer will be initialized in setupAndSample
            }
            object        
        })

.isSampleLogsConsistentWithChainSampler <- function(sampleLogs, chainSampler){
    isBlockDimensionsConsistentWith(getBlockDimensions(chainSampler), sampleLogs )
}

if(!exists("sampleLimiting")) setGeneric("sampleLimiting", function(object,...) standardGeneric("sampleLimiting"))
#' @export
setMethod("sampleLimiting", signature=c("PopulationSampler"),
        function(
                ### continue sampling aber burnin
                object                                  ##<< the Population sampler object
                ,nSample=3L*nRepresentativeRows         ##<< integer vector (nPopulation): number of samples to generate
                ,nSampleInitial=2*nRepresentativeRows   ##<< integer vector (nPopulation): number of samples to keep from end of previous sample
                ,nRepresentativeRows = computeNRepresentativeRows(getNParameterWithProposal(object@sampleLogs), getNChainInPopulation(object@sampleLogs))    
        ){
            sampleLogs(object) <- subsetTail( getSampleLogs(object), nSample=nSampleInitial)
            isBurnin(object) <- FALSE
            object <- setupAndSample(object, nSample=nSample)
            object
        })

#trace(setupAndSample, recover, signature = c("PopulationSampler"))    #untrace("setupAndSample", signature = c("PopulationSampler"), where =getNamespace("blockDemac"))
if(!exists("setupAndSample")) setGeneric("setupAndSample", function(object,...) standardGeneric("setupAndSample"))
#' @export
setMethod("setupAndSample", signature=c("PopulationSampler"),
        function(
                ### setup and perform the sampling
                object          ##<< the Population sampler object
                ,nSample        ##<< integer vector (nPopulation): number of samples to generate
                ,thin=4L        ##<< integer scalar: thinning interval used, i.e. after how many generations, a sample is recorded
                ,TStart = getEndTemperaturesPopulations(object@sampleLogs)     ##<< numeric scalar: initial temperature (or vector for components, or matrix for different populations)
                ,TEnd = TStart  ##<< numeric scalar: end temperature (or vector for components, or matrix for different populations)
                ,nIntervalPerRange = as.integer(round(computeNRepresentativeRows(getNParameter(object@sampleLogs), getNChainInPopulation(object@sampleLogs))/8))    ##<< combine sampling jumps for the as many thinning intervals
        ){
            force(TStart)   # else Start temperature is calcualted for extended SamplLogs
            if( length(nSample)==1 ) nSample <- rep(nSample, getNPopulation(object@sampleLogs))
            # initialize thinning interval of chain sampler 
            thin(object@chainSampler) <- thin
            #subSpacePopulations(object) <- subSpacePopulations
            object@nSampleBeforeSampling <- getNSamplePopulations(object@sampleLogs)
            object@nSampleBatchPopulations <- nSample
            object@nIntervalPerRange <- nIntervalPerRange
            # allocate space for new samples
            nSamplePopulations(object@sampleLogs) <- object@nSampleBeforeSampling + object@nSampleBatchPopulations
            # setup step temperatures
            object <- .initializeStepTemperatures(object, TStart=TStart,TEnd=TEnd)
            # set chain states to end of sampleLog
            x0 <- getParametersForPopulation(object@sampleLogs,1L)[,object@nSampleBeforeSampling[1L],1L]
            object@chainStates <- .initChainStates(
                  object@sampleLogs
                , iSamplePopulations=object@nSampleBeforeSampling
                , intermediateIds = getIntermediateIdsUsed(object@chainSampler)
                )
            object@acceptanceTracker <- resetAcceptanceTracker(object@acceptanceTracker
                    ,sampleDimensions=getSampleDimensions(object@sampleLogs)
                    , nSample=object@nSampleBatchPopulations
                    , nIntervalPerRange=object@nIntervalPerRange)
            object <- .resetJumpProposer(object, isBurnin=object@isBurnin)    # depends on thinning 
            # export things that do not change over sampling to remote processes
            if (.isParallel(object@cluster)){
                mcCommon <- .getMcCommon(object)
                #clusterExport(object@cluster, c("mcCommon", ".sampleRangeOneChain"), environment())  
                clusterExport(object@cluster, c("mcCommon"), environment())  
            } 
            object <- .samplePopulations(object)
            object
        })


#trace(blockDemac:::.initializeStepTemperatures, recover, signature = c("PopulationSampler"), where =getNamespace("blockDemac"))    #untrace("blockDemac:::.initializeStepTemperatures", signature = c("PopulationSampler"), where =getNamespace("blockDemac"))
if(!exists(".initializeStepTemperatures")) setGeneric(".initializeStepTemperatures", function(object,...) standardGeneric(".initializeStepTemperatures"))
setMethod(".initializeStepTemperatures", signature=c("PopulationSampler"),
        function( object
                , TStart = 1
                , TEnd = 1
        ){  
            object@stepTemperaturesPopulations <- .computeTemperatureDecreasePopulations(object, TStart, TEnd)
            thin <- getThin(object@chainSampler)
            thinnedStepTemperatures <- lapply(object@stepTemperaturesPopulations, function(stepTemperatures){
                        iSteps <- seq(thin,ncol(stepTemperatures),by=thin)
                        stepTemperatures[,iSteps ,drop=FALSE]
                    })
            stepTemperaturesPopulations(object@sampleLogs, iSample0=object@nSampleBeforeSampling) <- thinnedStepTemperatures             
            object
        })

if(!exists(".computeTemperatureDecreasePopulations")) setGeneric(".computeTemperatureDecreasePopulations", function(object,...) standardGeneric(".computeTemperatureDecreasePopulations"))
setMethod(".computeTemperatureDecreasePopulations", signature=c("PopulationSampler"),
        function( object
                ### Calculates the temperature for an exponential decrease from \code{TStart} to \code{Tend} after \code{nGen} steps. 	
                , TStart=1	    ##<< numeric matrix (nLogDensityComponents, nPopulation): the initial temperature (before the first step at iGen=0)
                , TEnd=1	##<< numeric matrix (nLogDensityComponents, nPopulation): the initial temperature (before the first step at iGen=0)
        ){
            if( !length(object@nSampleBatchPopulations) ) stop("nSampleBatchPopulations not initialized.")
            nGen <- object@nSampleBatchPopulations * getThin(object@chainSampler)
            nPop <- length(nGen)
            nLogDensityComponent <- getNLogDensityComponent(object@sampleLogs)
            if( nLogDensityComponent == 0){
                # return matrices with 0 rows
                res <- lapply(1:nPop, function(iPop){
                            matrix( NA_real_, nrow=0, ncol=nGen[iPop])
                        })
                return( res )
            }
            TStartM <- .formatPopulationTemperatures(object, TStart)
            TEndM <- .formatPopulationTemperatures(object, TEnd)
            lapply( 1:nPop, function(iPop){
                        t(.computeExponentialDecreaseVector(TStart=TStartM[,iPop],TEnd=TEndM[,iPop],nGen=nGen[iPop]))  
                    })
        })

if(!exists(".formatPopulationTemperatures")) setGeneric(".formatPopulationTemperatures", function(object,...) standardGeneric(".formatPopulationTemperatures"))
setMethod(".formatPopulationTemperatures", signature=c("PopulationSampler"),
        function(object,
                ### convert temperature specification to proper format for each population and logDensity component
                temperature     ##<< temperature (matrix, vector, scalar)
        ){
            ans <- temperature
            nPop <- getNPopulation(getSampleLogs(object))
            logDensityComponentNames <- getLogDensityComponentNames(getSampleLogs(object))
            nLogDensityComponent <- length(logDensityComponentNames)
            ##details<< if TStart or TEnd are given as vector, assume they refer to all populations.
            if( !is.matrix(ans) ) ans <- matrix(ans, nrow=length(ans), ncol=nPop)
            if( nLogDensityComponent > 1){
                ##details<< if rows in TStart or TEnd is one, assume they refer to all logDensityComponents
                if( nrow(ans)==1 ) ans <- matrix( ans, byrow=TRUE, nrow=nLogDensityComponent, ncol=ncol(ans))
            }
            if( nrow(ans) != nLogDensityComponent ) stop("number of rows in temperature must correspond to number of LogDensityComponents.")
            if( ncol(ans) != nPop ) stop("number of columns in temperature must correspond to number of populations.")
            rownames(ans) <- logDensityComponentNames
            ans
        })


if(!exists(".resetJumpProposer")) setGeneric(".resetJumpProposer", function(object,...) standardGeneric(".resetJumpProposer"))
setMethod(".resetJumpProposer", signature="PopulationSampler", 
        function(object, isBurnin=TRUE) {
            iParametersThatRequireJumpProposal <- getIParametersThatRequireJumpProposal(object@chainSampler)
            object@jumpProposer <- initializeDimensionalSettings(object@jumpProposer
                    , sampleDimensions=getSampleDimensions(object)
                    , thin=getThin(object@chainSampler)
                    , iParametersThatRequireJumpProposal=iParametersThatRequireJumpProposal )
            object@jumpProposer@isBurnin <- isBurnin
            object
        })



if(!exists(".samplePopulations")) setGeneric(".samplePopulations", function(object, ...) standardGeneric(".samplePopulations"))
setMethod(".samplePopulations", signature=c("PopulationSampler"),
        function(object){
            # (each nIntervalPersRange thinning intervals times thin generations)
            # Instead of handling all populations separately, in each step all participating  
            # chains are combined to a big array, to best use parallel calculation.
            # However, some populations may need fewer thinning steps. 
            # Hence, track is kept of the chains that still take part.
            iSampleInBatch <- 1L
            # populations that take part in this step (some may need fewer steps)
            iPopulationsStep <- which( object@nSampleBatchPopulations >= iSampleInBatch)   
            while( length(iPopulationsStep) ){    # as long as some populations participating (all thinning steps)
                # thinning interval after which fewer populations take part
                nSampleBatchMin <- min( object@nSampleBatchPopulations[iPopulationsStep] )   
                while( iSampleInBatch <= nSampleBatchMin ){
                    # anticipate that nIntervalPerRange may overshooting nSampleBatchMin
                    nThinningIntervalStep <- min(object@nIntervalPerRange, nSampleBatchMin - iSampleInBatch + 1L )
                    .signalProgress(object@progressOutput)
                    object <- .proposeSampleAndLogRange(object
                            ,iPopulationsStep=iPopulationsStep
                            ,iSampleInBatch=iSampleInBatch
                            ,nThinningIntervalStep=nThinningIntervalStep
                    )
                    iSampleInBatch <- iSampleInBatch + nThinningIntervalStep        
                } # end not change in participating populations
                # update populations that take part in the following sequence of steps
                iPopulationsStep <- which( object@nSampleBatchPopulations >= iSampleInBatch)
                #if( length(iPopulationsStep) == 1 ) recover()        
            } # end main loop
            .signalProgress(object@progressOutput, appendLF = TRUE)
            object
        }
)

.tmp.f <- function(){
    #library(profr)
    p1 <- profr({
                for( i in 1:10 ){
                .proposeSampleAndLogRange(object
                        ,iPopulationsStep=iPopulationsStep
                        ,iSampleInBatch=iSampleInBatch
                        ,nThinningIntervalStep=nThinningIntervalStep
                )            
                }
            })
    plot(p1)
}

.signalProgress <- function(progressOutput, appendLF = FALSE){
    if( length(progressOutput) ) message(progressOutput, appendLF=appendLF)  
}

if(!exists(".getMcCommon")) setGeneric(".getMcCommon", function(object, ...) standardGeneric(".getMcCommon"))
setMethod(".getMcCommon", signature=c("PopulationSampler"),
        function(object){
            mcCommon <- list(
                    chainSampler = object@chainSampler
                    ,subSpacePopulations = object@subSpacePopulations
                    ,temperatures = object@stepTemperaturesPopulations
                    ,sampleDimensions = getSampleDimensions(object@sampleLogs)
            )
        })
        

if(!exists(".proposeSampleAndLogRange")) setGeneric(".proposeSampleAndLogRange", function(object,...) standardGeneric(".proposeSampleAndLogRange"))
setMethod(".proposeSampleAndLogRange", signature=c("PopulationSampler"),
        function(object, iPopulationsStep, iSampleInBatch, nThinningIntervalStep){  # as long as the same populations take part
            iChainsStep <- getIChainsForPopulations(getSampleDimensions(object@sampleLogs), iPopulationsStep)
            pAcceptPops  <- computePopulationAcceptanceRates(object@acceptanceTracker)
            iPopulationChains <- getIPopulationsForChains(getSampleDimensions(object@sampleLogs), iChainsStep)
            pAcceptChains <- pAcceptPops[iPopulationChains]
            # jumps relate already only to the populations taking part in this range (iPopulationsStep)
            object@jumpProposer <- adjustToAcceptanceRate(object@jumpProposer, acceptanceTracker = object@acceptanceTracker)
            jumps <- proposeJumps( object@jumpProposer
                    , nGeneration=nThinningIntervalStep*getThin(object@chainSampler)
                    , sampleLogs=object@sampleLogs
                    , iPopulationsStep = iPopulationsStep
                    , iCurrentSamples = object@nSampleBeforeSampling+iSampleInBatch-1  # current state before the current index
            )
            # samplesChains also takes information of the participating populations
            samplesChains <- sampleRangeAllChains(object
            #samplesChains <- blockDemac:::sampleRangeAllChains(object
                    , chainStates = object@chainStates[iChainsStep]
                    , intervalInfoChains =list(
                            iChainsStep=iChainsStep
                            ,iSample0=iSampleInBatch-1
                            ,nSample=nThinningIntervalStep
                            ,step=jumps$jump
                            , rExtra=jumps$logSnookerDensityMultiplier
                            , pAccept=pAcceptChains
                    ), mcCommon=blockDemac:::.getMcCommon(object))
            # samplesChains holds only the participating chains
            object@chainStates[iChainsStep] <- lapply( samplesChains, "[[", "chainState" )
            sampleLogChains <- lapply( samplesChains, "[[", "sampleLog" )
            object@sampleLogs <- recordSampleLogChains(object@sampleLogs, sampleLogChains
                    , iPopulations=iPopulationsStep, iSample0=object@nSampleBeforeSampling+iSampleInBatch-1 )
            proportionAcceptedInInterval <- abind( lapply(sampleLogChains, getProportionAcceptedInInterval), rev.along=0)
            object@acceptanceTracker <- recordAcceptanceRate(object@acceptanceTracker, proportionAcceptedInInterval=proportionAcceptedInInterval, iChains=iChainsStep)
            object
        })


.initChainStates <- function(
        ### Initialize chainState to given recored sample
        sampleLogs         ##<< SampleLogs Object
        ,iPopulations=1:getNPopulation(sampleLogs)      ##<< integer vector of populations that take part 
        ,iSamplePopulations=getNSamplePopulations(sampleLogs)[iPopulations]  ##<< integer vector (length iPopulations): index of the sample to put to chainState for each population
        ,intermediateIds=character(0)   ##<< names of the intermediates, that will be initialized to "not up to date, i.e. empty list"         
        ,chainStates         ##<< list of ChainState objects to initialize
){
    if( missing(chainStates) ){
        chainStates <- rep(list(new("ChainState",getParametersAndInitialForPopulation(sampleLogs,1L)[,1L,1L] )), getNChain(sampleLogs))
    }
    iChains <- as.vector(sapply( iPopulations, function(iPop){ getIChainsForPopulation(sampleLogs,iPop) }))
    sampleLogChains <- getSampleLogChainsForPopulations(sampleLogs, iPopulations)
    iSampleChains <- rep(iSamplePopulations,each=getNChainInPopulation(sampleLogs))
    intermediates <- structure( rep( list(list()), times=length(intermediateIds)), names=intermediateIds )
    updatedChainStates <- mapply( function(chainState, sampleLogChain, iSample){
                intermediates(chainState) <- intermediates
                initializeFromSampleLogChain(chainState, sampleLogChain, iSample)
            }, chainState=chainStates[iChains], sampleLogChain=sampleLogChains, iSample=iSampleChains)
    updatedChainStates
    
}

if(!exists("sampleBurnedIn")) 


if(!exists("getSampleDimensions")) setGeneric("getSampleDimensions", function(object) standardGeneric("getSampleDimensions"))
setMethod("getSampleDimensions", signature="PopulationSampler", function(object) {getSampleDimensions(object@sampleLogs)})


modifyIntermediateInSampler <- function(
    ### change something in intermediate of given population sampler
    sampler             ##<< PopulationSampler object
    ,intermediateName   ##<< name of the intermediate to change
    , fModify=function(intermediate,...){intermediate}  ##<< function that receives an IntermediateUpdater object and returns one
    ,...    ##<< further arguments to fModify
){
    sampler@chainSampler@blockUpdaters@intermediateUpdaters@intermediateUpdaters[[intermediateName]] <-
            fModify(sampler@chainSampler@blockUpdaters@intermediateUpdaters@intermediateUpdaters[[intermediateName]])
    ##value<< a modified sampler object keeping all sampleLogs
    sampler
}
attr(modifyIntermediateInSampler,"modifyIntermediateInSampler") <- function(){
    if( FALSE ) {
        # sometimes an update of the additional parameters to the intermediate is required before continued sampling
        sampler2 <- modifyIntermediateInSampler(sampler, "deltaA_rich", function(im){
                    im@argsUpdateFunction$minSd2DiscrFractionVal <- 1/20
                    im
                })
    }
}

if(!exists("setNoCluster")) setGeneric("setNoCluster", function(object,...) standardGeneric("setNoCluster"))
#' @export
setMethod("setNoCluster", signature="PopulationSampler", 
        function( object
        ### Set to not usiung any cluster
        ){
            object@cluster <- structure(list(),class=c("SOCKcluster","cluster"))
            object
        })


if(!exists("getBlockDimensions")) setGeneric("getBlockDimensions", function(object) standardGeneric("getBlockDimensions"))
setMethod("getBlockDimensions", signature="PopulationSampler", function(object) { getBlockDimensions(object@chainSampler)})


#library(twDev)    # automatic generation of GSetter
#--- generateAndPrintS4GSetters("PopulationSampler")
if(!exists("getChainStates")) setGeneric("getChainStates", function(object) standardGeneric("getChainStates"))
#' @export
setMethod("getChainStates", signature="PopulationSampler", function(object) {object@chainStates})
#if(!exists("chainStates<-")) setGeneric("chainStates<-", function(object,value) standardGeneric("chainStates<-"))
#setReplaceMethod("chainStates", signature=c("PopulationSampler", "list"), function(object, value) {object@chainStates <- value; object})

if(!exists("getSampleLogs")) setGeneric("getSampleLogs", function(object) standardGeneric("getSampleLogs"))
#' @export
setMethod("getSampleLogs", signature="PopulationSampler", function(object) {object@sampleLogs})

if(!exists("getChainSampler")) setGeneric("getChainSampler", function(object) standardGeneric("getChainSampler"))
#' @export
setMethod("getChainSampler", signature="PopulationSampler", function(object) {object@chainSampler})
if(!exists("chainSampler<-")) setGeneric("chainSampler<-", function(object,value) standardGeneric("chainSampler<-"))
#' @export
setReplaceMethod("chainSampler", signature=c("PopulationSampler", "ChainSamplerImpl"), function(object, value) {
            if( !(.isSampleLogsConsistentWithChainSampler(object@sampleLogs, value)) ){ 
                warning("Setting inconsistent ChainSampler invalidates sampleLogs. Need to set sampleLogs again.")
                object@sampleLogs <- new("SampleLogs")
            }
            object@chainSampler <- value
            blockDimensions(object@sampleLogs) <- getBlockDimensions(object@chainSampler)
            object            
        })

if(!exists("jumpProposer<-")) setGeneric("jumpProposer<-", function(object,value) standardGeneric("jumpProposer<-"))
#' @export
setReplaceMethod("jumpProposer", signature=c("PopulationSampler", "JumpProposer"), function(object, value) {
            object@jumpProposer <- value
            object <- .resetJumpProposer(object)
            object
        })

if(!exists("getAcceptanceTracker")) setGeneric("getAcceptanceTracker", function(object) standardGeneric("getAcceptanceTracker"))
#' @export
setMethod("getAcceptanceTracker", signature="PopulationSampler", function(object) {object@acceptanceTracker})
if(!exists("acceptanceTracker<-")) setGeneric("acceptanceTracker<-", function(object,value) standardGeneric("acceptanceTracker<-"))
#' @export
setReplaceMethod("acceptanceTracker", signature=c("PopulationSampler", "AcceptanceTracker"), function(object, value) {
            stop("not implemented yet. initialize object")
            object@acceptanceTracker <- value; object
        })

if(!exists("getProgressOutput")) setGeneric("getProgressOutput", function(object) standardGeneric("getProgressOutput"))
#' @export
setMethod("getProgressOutput", signature="PopulationSampler", function(object) {object@progressOutput})
if(!exists("progressOutput<-")) setGeneric("progressOutput<-", function(object,value) standardGeneric("progressOutput<-"))
#' @export
setReplaceMethod("progressOutput", signature=c("PopulationSampler", "character"), function(object, value) {object@progressOutput <- value; object})

if(!exists("getSubSpacePopulations")) setGeneric("getSubSpacePopulations", function(object) standardGeneric("getSubSpacePopulations"))
setMethod("getSubSpacePopulations", signature="PopulationSampler", function(object) {object@subSpacePopulations})
if(!exists("subSpacePopulations<-")) setGeneric("subSpacePopulations<-", function(object,value) standardGeneric("subSpacePopulations<-"))
setReplaceMethod("subSpacePopulations", signature=c("PopulationSampler", "list"), function(object, value) {
            if( length(value) != getNPopulation(object@sampleLogs)) stop("Need to provide a subspace for each population.")
            if( !all(sapply(value, is, "SubSpace"))) stop("Need to provide SubSpace objects.")
            subSpaces <- lapply( value, initializeIndexedBoundsForParameterNames, parameterNames=getParameterNames(object@sampleLogs))            
            object@subSpacePopulations <- subSpaces 
            object
        })

if(!exists("isBurnin")) setGeneric("isBurnin", function(object,...) standardGeneric("isBurnin"))
#' @export
setMethod("isBurnin", signature="PopulationSampler", function(object,...
        ### Getter method for slot isBurnin
        ) {object@isBurnin})
if(!exists("isBurnin<-")) setGeneric("isBurnin<-", function(object,value) standardGeneric("isBurnin<-"))
#' @export
setReplaceMethod("isBurnin", signature=c("PopulationSampler", "logical"), function(object, value
        ### Setter method for slot isBurnin
        ) {object@isBurnin <- value; object})

if(!exists("getNRepresentativeRows")) setGeneric("getNRepresentativeRows", function(object,...) standardGeneric("getNRepresentativeRows"))
#' @export
setMethod("getNRepresentativeRows", signature="PopulationSampler", function(object,...
        ### Getter method for slot nRepresentativeRows
        ) {object@nRepresentativeRows})

Try the blockDemac package in your browser

Any scripts or data that you put into this service are public.

blockDemac documentation built on May 2, 2019, 4:52 p.m.