Program Listing for File GWRMultiscale.h

Return to documentation for file (include/gwmodelpp/GWRMultiscale.h)

#ifndef GWRMULTISCALE_H
#define GWRMULTISCALE_H

#include <utility>
#include <string>
#include <initializer_list>
#include <optional>
#include "SpatialMultiscaleAlgorithm.h"
#include "spatialweight/SpatialWeight.h"
#include "IRegressionAnalysis.h"
#include "IBandwidthSelectable.h"
#include "BandwidthSelector.h"
#include "IParallelizable.h"


namespace gwm
{

#define GWM_LOG_TAG_MGWR_INITIAL_BW "#initial-bandwidth "
#define GWM_LOG_TAG_MGWR_BACKFITTING "#back-fitting "

#define GWM_LOG_MGWR_BACKFITTING(MESSAGE) { GWM_LOG_INFO((std::string(GWM_LOG_TAG_MGWR_BACKFITTING) + (MESSAGE))); }

class GWRMultiscale : public SpatialMultiscaleAlgorithm,
    public IBandwidthSelectable,
    public IRegressionAnalysis,
    public IParallelizable,
    public IParallelOpenmpEnabled,
    public IParallelCudaEnabled,
    public IParallelMpiEnabled
{
public:

    enum BandwidthInitilizeType
    {
        Null,
        Initial,
        Specified
    };

    static std::unordered_map<BandwidthInitilizeType,std::string> BandwidthInitilizeTypeNameMapper;

    enum BandwidthSelectionCriterionType
    {
        CV,
        AIC
    };

    static std::unordered_map<BandwidthSelectionCriterionType,std::string> BandwidthSelectionCriterionTypeNameMapper;

    enum BackFittingCriterionType
    {
        CVR,
        dCVR
    };

    static std::unordered_map<BackFittingCriterionType,std::string> BackFittingCriterionTypeNameMapper;

    typedef double (GWRMultiscale::*BandwidthSizeCriterionFunction)(BandwidthWeight*);

    typedef arma::vec (GWRMultiscale::*FitVarFunction)(const size_t);

    typedef arma::vec (GWRMultiscale::*FitVarCoreFunction)(const arma::vec&, const arma::vec&, const SpatialWeight&, arma::mat&);

    typedef arma::vec (GWRMultiscale::*FitVarCoreCVFunction)(const arma::vec&, const arma::vec&, const SpatialWeight&);

    typedef arma::vec (GWRMultiscale::*FitVarCoreSHatFunction)(const arma::vec&, const arma::vec&, const SpatialWeight&, arma::vec&);

private:

    static arma::vec Fitted(const arma::mat& x, const arma::mat& betas)
    {
        return sum(betas % x, 1);
    }

    static double RSS(const arma::mat& x, const arma::mat& y, const arma::mat& betas)
    {
        arma::vec r = y - Fitted(x, betas);
        return sum(r % r);
    }

    static double AICc(const arma::mat& x, const arma::mat& y, const arma::mat& betas, const arma::vec& shat)
    {
        double ss = RSS(x, y, betas), n = (double)x.n_rows;
        return n * log(ss / n) + n * log(2 * arma::datum::pi) + n * ((n + shat(0)) / (n - 2 - shat(0)));
    }

    bool isStoreS()
    {
        return mHasHatMatrix && (mCoords.n_rows < 8192);
    }

    static RegressionDiagnostic CalcDiagnostic(const arma::mat &x, const arma::vec &y, const arma::vec &shat, double RSS);

    void setInitSpatialWeight(const SpatialWeight &spatialWeight)
    {
        mInitSpatialWeight = spatialWeight;
    }

public:

    GWRMultiscale() {}

    GWRMultiscale(const arma::mat& x, const arma::vec& y, const arma::mat& coords, const std::vector<SpatialWeight>& spatialWeights)
        : SpatialMultiscaleAlgorithm(coords, spatialWeights)
    {
        mX = x;
        mY = y;
        if (spatialWeights.size() > 0)
            setInitSpatialWeight(spatialWeights[0]);
    }

    virtual ~GWRMultiscale() {}

public:

    void setGoldenUpperBounds(double value) { mGoldenUpperBounds = value; }

    void setGoldenLowerBounds(double value) { mGoldenLowerBounds = value; }

    const std::vector<BandwidthInitilizeType>& bandwidthInitilize() const { return GWRMultiscale::mBandwidthInitilize; }

    void setBandwidthInitilize(const std::vector<BandwidthInitilizeType> &bandwidthInitilize);

    const std::vector<BandwidthSelectionCriterionType>& bandwidthSelectionApproach() const { return GWRMultiscale::mBandwidthSelectionApproach; }

    void setBandwidthSelectionApproach(const std::vector<BandwidthSelectionCriterionType> &bandwidthSelectionApproach);

    const std::vector<bool>& preditorCentered() const { return mPreditorCentered; }

    void setPreditorCentered(const std::vector<bool> &preditorCentered) { mPreditorCentered = preditorCentered; }

    const std::vector<double>& bandwidthSelectThreshold() const { return mBandwidthSelectThreshold; }

    void setBandwidthSelectThreshold(const std::vector<double> &bandwidthSelectThreshold) { mBandwidthSelectThreshold = bandwidthSelectThreshold; }

    bool hasHatMatrix() const { return mHasHatMatrix; }

    void setHasHatMatrix(bool hasHatMatrix) { mHasHatMatrix = hasHatMatrix; }

    size_t bandwidthSelectRetryTimes() const { return (size_t)mBandwidthSelectRetryTimes; }

    void setBandwidthSelectRetryTimes(size_t bandwidthSelectRetryTimes) { mBandwidthSelectRetryTimes = (arma::uword)bandwidthSelectRetryTimes; }

    size_t maxIteration() const { return mMaxIteration; }

    void setMaxIteration(size_t maxIteration) { mMaxIteration = maxIteration; }

    BackFittingCriterionType criterionType() const { return mCriterionType; }

    void setCriterionType(const BackFittingCriterionType &criterionType) { mCriterionType = criterionType; }

    double criterionThreshold() const { return mCriterionThreshold; }

    void setCriterionThreshold(double criterionThreshold) { mCriterionThreshold = criterionThreshold; }

    int adaptiveLower() const { return mAdaptiveLower; }

    void setAdaptiveLower(int adaptiveLower) { mAdaptiveLower = adaptiveLower; }

    const arma::mat& betas() const { return mBetas; }

    BandwidthSizeCriterionFunction bandwidthSizeCriterionVar(BandwidthSelectionCriterionType type);

public:     // SpatialAlgorithm interface
    bool isValid() override;


public:     // SpatialMultiscaleAlgorithm interface
    virtual void setSpatialWeights(const std::vector<SpatialWeight> &spatialWeights) override;


public:     // IBandwidthSizeSelectable interface
    Status getCriterion(BandwidthWeight* weight, double& criterion) override
    {
        criterion = (this->*mBandwidthSizeCriterion)(weight);
        return mStatus;
    }


public:     // IRegressionAnalysis interface
    virtual const arma::vec& dependentVariable() const override { return mY; }
    virtual void setDependentVariable(const arma::vec& y) override { mY = y; }

    virtual const arma::mat& independentVariables() const override { return mX; }
    virtual void setIndependentVariables(const arma::mat& x) override { mX = x; }

    virtual bool hasIntercept() const override { return mHasIntercept; }
    virtual void setHasIntercept(const bool has) override { mHasIntercept = has; }

    virtual RegressionDiagnostic diagnostic() const override { return mDiagnostic; }

    arma::mat predict(const arma::mat& locations) override { return arma::mat(locations.n_rows, mX.n_cols, arma::fill::zeros); }

    arma::mat fit() override;

public:     // IParallelalbe interface
    int parallelAbility() const override
    {
        return ParallelType::SerialOnly
#ifdef ENABLE_OPENMP
            | ParallelType::OpenMP
#endif
#ifdef ENABLE_CUDA
            | ParallelType::CUDA
#endif
            ;
    }

    ParallelType parallelType() const override { return mParallelType; }

    void setParallelType(const ParallelType &type) override;


public:     // IOpenmpParallelable interface
    void setOmpThreadNum(const int threadNum) override { mOmpThreadNum = threadNum; }

public:     // IParallelCudaEnabled interface
    void setGPUId(const int gpuId) override { mGpuId = gpuId; }
    void setGroupSize(const std::size_t size) override { mGroupLength = size; }
    int workerId() override { return mWorkerId; }
    void setWorkerId(int id) override { mWorkerId = id; };
    void setWorkerNum(int size) override { mWorkerNum = size; };

protected:

    BandwidthWeight* bandwidth(size_t i)
    {
        return mSpatialWeights[i].weight<BandwidthWeight>();
    }

    arma::mat fitInitial();

    arma::mat backfitting(const arma::mat& betas0);

    arma::vec fitVarBase(const size_t var);

    double bandwidthSizeCriterionVarCVBase(BandwidthWeight* bandwidthWeight);

    double bandwidthSizeCriterionVarAICBase(BandwidthWeight* bandwidthWeight);

    arma::vec fitVarCoreSerial(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::mat& S);

    arma::vec fitVarCoreCVSerial(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw);

    arma::vec fitVarCoreSHatSerial(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::vec& shat);

#ifdef ENABLE_OPENMP
    arma::vec fitVarCoreOmp(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::mat& S);

    arma::vec fitVarCoreCVOmp(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw);

    arma::vec fitVarCoreSHatOmp(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::vec& shat);
#endif

#ifdef ENABLE_CUDA

    arma::vec fitVarCoreCuda(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::mat& S);

    arma::vec fitVarCoreCVCuda(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw);

    arma::vec fitVarCoreSHatCuda(const arma::vec& x, const arma::vec& y, const SpatialWeight& sw, arma::vec& shat);

#endif // ENABLE_CUDA

#ifdef ENABLE_MPI
    arma::vec fitVarMpi(const size_t var);
    double bandwidthSizeCriterionVarCVMpi(BandwidthWeight* bandwidthWeight);
    double bandwidthSizeCriterionVarAICMpi(BandwidthWeight* bandwidthWeight);
#endif // ENABLE_MPI

private:
    FitVarFunction mFitVar = &GWRMultiscale::fitVarBase;
    FitVarCoreFunction mFitVarCore = &GWRMultiscale::fitVarCoreSerial;
    FitVarCoreCVFunction mFitVarCoreCV = &GWRMultiscale::fitVarCoreCVSerial;
    FitVarCoreSHatFunction mFitVarCoreSHat = &GWRMultiscale::fitVarCoreSHatSerial;

    SpatialWeight mInitSpatialWeight;
    BandwidthSizeCriterionFunction mBandwidthSizeCriterion = &GWRMultiscale::bandwidthSizeCriterionVarCVBase;
    size_t mBandwidthSelectionCurrentIndex = 0;
    double mBandwidthLastCriterion = DBL_MAX;
    std::optional<double> mGoldenUpperBounds;
    std::optional<double> mGoldenLowerBounds;
    std::vector<double> mMaxDistances;
    std::vector<double> mMinDistances;

    std::vector<BandwidthInitilizeType> mBandwidthInitilize;
    std::vector<BandwidthSelectionCriterionType> mBandwidthSelectionApproach;
    std::vector<bool> mPreditorCentered;
    std::vector<double> mBandwidthSelectThreshold;
    arma::uword mBandwidthSelectRetryTimes = 5;
    size_t mMaxIteration = 500;
    BackFittingCriterionType mCriterionType = BackFittingCriterionType::dCVR;
    double mCriterionThreshold = 1e-6;
    int mAdaptiveLower = 10;

    bool mHasHatMatrix = true;

    arma::mat mX;
    arma::vec mY;
    arma::mat mBetas;
    arma::mat mBetasSE;
    arma::mat mBetasTV;
    bool mHasIntercept = true;

    arma::mat mS0;
    arma::cube mSArray;
    arma::cube mC;
    arma::mat mX0;
    arma::vec mY0;
    arma::vec mXi;
    arma::vec mYi;

    double mRSS0;

    RegressionDiagnostic mDiagnostic;

    ParallelType mParallelType = ParallelType::SerialOnly;
    int mOmpThreadNum = 8;
    size_t mGroupLength = 64;
    int mGpuId = 0;
    int mWorkerId = 0;
    int mWorkerNum = 1;
#ifdef ENABLE_MPI
    arma::uword mWorkRangeSize = 0;
#endif // ENABLE_MPI
    std::pair<arma::uword, arma::uword> mWorkRange = std::make_pair(arma::uword(0), arma::uword(0));

public:
    static int treeChildCount;
};

}

#endif // GWRMULTISCALE_H