411 std::vector<helper::RasterBandMetaData>& bands,
424 std::vector<std::vector<T>> probabilities(count);
427 for (
int i = 0; i < count; i++) {
428 probabilities[i].resize(nSamp - 1);
431 for (
int j = 0; j < nSamp - 1; j++) {
432 probabilities[i][j] =
static_cast<T
>(j + 1) /
static_cast<T
>(nSamp);
436 int xBlockSize = bands[0].xBlockSize;
437 int yBlockSize = bands[0].yBlockSize;
439 int xBlocks = (width + xBlockSize - 1) / xBlockSize;
440 int yBlocks = (height + yBlockSize - 1) / yBlockSize;
445 std::vector<T> corrBuffer(count * xBlockSize * yBlockSize);
446 std::vector<std::vector<T>> quantileBuffers(count);
447 for (
int i = 0; i < count; i++) {
448 quantileBuffers[i].resize(xBlockSize * yBlockSize);
452 access.band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize,
access.band.size);
456 const auto cor_desc = oneapi::dal::covariance::descriptor{}.set_result_options(oneapi::dal::covariance::result_options::cor_matrix);
457 oneapi::dal::covariance::partial_compute_result<> partial_result;
460 std::vector<VSLSSTaskPtr> quantileTasks(count);
462 MKL_INT quant_order_n =
quantiles[0].size();
464 MKL_INT n = xBlockSize * yBlockSize;
465 MKL_INT nparams = VSL_SS_SQUANTS_ZW_PARAMS_N;
466 MKL_INT xstorage = VSL_SS_MATRIX_STORAGE_ROWS;
469 if (type == GDT_Float64) {
470 for (
int i = 0; i < count; i++) {
472 status = vsldSSNewTask(
477 reinterpret_cast<double *
>(quantileBuffers[i].data()),
484 for (
int i = 0; i < count; i++) {
486 status = vslsSSNewTask(
491 reinterpret_cast<float *
>(quantileBuffers[i].data()),
498 int8_t *p_access =
reinterpret_cast<int8_t *
>(
access.band.p_buffer);
500 bool calledEditStreamQuantiles =
false;
501 void *p_data =
reinterpret_cast<void *
>(corrBuffer.data());
503 for (
int yBlock = 0; yBlock < yBlocks; yBlock++) {
504 for (
int xBlock = 0; xBlock < xBlocks; xBlock++) {
507 bands[0].p_band->GetActualBlockSize(xBlock, yBlock, &xValid, &yValid);
510 for (
int i = 0; i < count ; i++) {
511 CPLErr err = bands[i].p_band->RasterIO(
517 (
void *)((
size_t)p_data + i * size),
521 size *
static_cast<size_t>(count),
522 size *
static_cast<size_t>(count) *
static_cast<size_t>(xBlockSize)
526 throw std::runtime_error(
"Error reading data from raster band.");
535 rasterBandIO(
access.band,
access.band.p_buffer, xBlockSize, yBlockSize, xBlock, yBlock, xValid, yValid,
true,
false);
540 for (
int y = 0; y < yValid; y++) {
541 int index = y * xBlockSize;
542 for (
int x = 0; x < xValid; x++) {
544 T *p_buff = corrBuffer.data() + (index * count);
545 for (
int b = 0; b < count; b++) {
547 isNan = std::isnan(val) || val == bands[b].nan;
553 quantileBuffers[b][n] = val;
554 corrBuffer[n * count + b] = val;
560 bool accessible = !
access.used || p_access[index] != 1;
562 if (
existing.used &&
existing.containsIndex(x + xBlock * xBlockSize, y + yBlock * yBlockSize)) {
563 clhs.addExistingPoint(
565 xBlock * xBlockSize + x,
566 yBlock * yBlockSize + y
569 else if (accessible && rand.
next()) {
572 xBlock * xBlockSize + x,
573 yBlock * yBlockSize + y
586 if (type == GDT_Float64) {
587 if (!calledEditStreamQuantiles) {
588 for (
int i = 0; i < count; i++) {
590 status = vsldSSEditStreamQuantiles(
593 reinterpret_cast<double *
>(probabilities[i].data()),
594 reinterpret_cast<double *
>(
quantiles[i].data()),
599 calledEditStreamQuantiles =
true;
601 for (
int i = 0; i < count; i++) {
602 status = vsldSSCompute(
604 VSL_SS_STREAM_QUANTS,
605 VSL_SS_METHOD_SQUANTS_ZW_FAST
610 if (!calledEditStreamQuantiles) {
611 for (
int i = 0; i < count; i++) {
613 status = vslsSSEditStreamQuantiles(
616 reinterpret_cast<float *
>(probabilities[i].data()),
617 reinterpret_cast<float *
>(
quantiles[i].data()),
622 calledEditStreamQuantiles =
true;
624 for (
int i = 0; i < count; i++) {
625 status = vslsSSCompute(
627 VSL_SS_STREAM_QUANTS,
628 VSL_SS_METHOD_SQUANTS_ZW_FAST
635 DALHomogenTable table = DALHomogenTable(corrBuffer.data(), n, count, [](
const T *){}, oneapi::dal::data_layout::row_major);
636 partial_result = oneapi::dal::partial_compute(cor_desc, partial_result, table);
641 VSIFree(
access.band.p_buffer);
645 auto result = oneapi::dal::finalize_compute(cor_desc, partial_result);
646 auto correlation = result.get_cor_matrix();
648 oneapi::dal::row_accessor<const T> acc {correlation};
651 std::vector<std::vector<T>> corr(count);
652 for (
int i = 0; i < count; i++) {
653 corr[i].resize(count);
654 auto row = acc.pull({i, i + 1});
656 for (
int j = 0; j < count; j++) {
660 status = (type == GDT_Float64) ?
661 vsldSSCompute(quantileTasks[i], VSL_SS_STREAM_QUANTS, VSL_SS_METHOD_SQUANTS_ZW) :
662 vslsSSCompute(quantileTasks[i], VSL_SS_STREAM_QUANTS, VSL_SS_METHOD_SQUANTS_ZW);
663 status = vslSSDeleteTask(&quantileTasks[i]);
708 xso::xoshiro_4x64_plus& rng,
717 std::vector<double>& xCoords,
718 std::vector<double>& yCoords)
720 std::vector<T> features;
724 std::vector<int> sampleCountPerQuantile(nFeat * nSamp, 0);
725 std::vector<int> quantilesOfEachSample(nSamp * nFeat, 0);
729 clhs.getExistingFeatures(features, x, y);
735 size_t neSamples = x.size();
736 if (neSamples > 0 && replace != 0) {
737 for (
size_t si = 0; si < neSamples; si++) {
738 for (
size_t fi = 0; fi < nFeat; fi++) {
739 T val = features[(si * nFeat) + fi];
741 sampleCountPerQuantile[(fi * nSamp) + q]++;
742 quantilesOfEachSample[(si * nFeat) + fi] = q;
746 while (replace > 0 && neSamples > 0) {
747 size_t worstRedundancy = 0;
748 size_t worstRedundancyIndex = 0;
752 for (
size_t si = 0; si < neSamples; si++) {
753 size_t curSampleRedundancy = 0;
754 for (
size_t fi = 0; fi < nFeat; fi++) {
755 size_t q = quantilesOfEachSample[(si * nFeat) + fi];
756 curSampleRedundancy += sampleCountPerQuantile[(fi * nSamp) + q];
758 if (curSampleRedundancy > worstRedundancy) {
759 worstRedundancy = curSampleRedundancy;
760 worstRedundancyIndex = si;
767 if (worstRedundancy == nFeat) {
773 size_t si = worstRedundancyIndex;
774 for (
size_t fi = 0; fi < nFeat; fi++) {
775 size_t q = quantilesOfEachSample[(si * nFeat) + fi];
776 sampleCountPerQuantile[(fi * nSamp) + q]--;
779 x[si] = x[neSamples - 1];
780 y[si] = y[neSamples - 1];
781 std::memcpy(features.data() + (si * nFeat),
782 features.data() + ((neSamples - 1) * nFeat),
784 std::memcpy(quantilesOfEachSample.data() + (si * nFeat),
785 quantilesOfEachSample.data() + ((neSamples - 1) * nFeat),
786 sizeof(
int) * nFeat);
797 size_t starti = neSamples;
798 boost::unordered::unordered_flat_set<uint64_t> points;
802 for (
size_t si = 0; si < neSamples; si++) {
803 OGRPoint point =
existing.getPoint(x[si], y[si]);
807 xCoords.push_back(point.getX());
808 yCoords.push_back(point.getY());
811 points.insert((((uint64_t) x[si]) << 32) | ((uint64_t) y[si]));
815 if (starti >= nSamp) {
819 std::uniform_real_distribution<T>
dist(0.0, 1.0);
820 std::uniform_int_distribution<size_t> indexDist(starti, nSamp - 1);
822 std::vector<std::vector<T>> corr(nFeat);
823 for (
int i = 0; i < nFeat; i++) {
824 corr[i].resize(nFeat);
827 features.resize(nSamp * nFeat);
835 clhs.getRandomPoint(p);
837 if (points.contains((((uint64_t) p.
x) << 32) | ((uint64_t) p.
y))) {
844 for (
int f = 0; f < nFeat; f++) {
846 features[(i * nFeat) + f] = val;
849 sampleCountPerQuantile[(f * nSamp) + q]++;
850 quantilesOfEachSample[(i * nFeat) + f] = q;
853 points.insert((((uint64_t) p.
x) << 32) | ((uint64_t) p.
y));
858 DALHomogenTable table = DALHomogenTable(features.data(), nSamp, nFeat, [](
const T *){}, oneapi::dal::data_layout::row_major);
859 const auto cor_desc = oneapi::dal::covariance::descriptor{}.set_result_options(oneapi::dal::covariance::result_options::cor_matrix);
860 const auto result = oneapi::dal::compute(cor_desc, table);
861 oneapi::dal::row_accessor<const T> acc {result.get_cor_matrix()};
862 for (
int i = 0; i < nFeat; i++) {
863 auto row = acc.pull({i, i + 1});
865 for (
int j = 0; j < nFeat; j++) {
871 double d = temp /
static_cast<double>(iterations);
874 T objQ =
clhs.quantileObjectiveFunc(sampleCountPerQuantile);
875 T objC =
clhs.correlationObjectiveFunc(corr);
880 std::vector<T> oldf(nFeat);
883 while (temp > 0 && objQ != 0) {
885 if (
dist(rng) < 0.5) {
894 size_t worstRedundancyIndex = 0;
895 size_t worstRedundancy = 0;
896 for (
size_t si = starti; si < nSamp; si++) {
897 size_t curSampleRedundancy = 0;
898 for (
size_t fi = 0; fi < nFeat; fi++) {
899 size_t q = quantilesOfEachSample[(si * nFeat) + fi];
900 curSampleRedundancy += sampleCountPerQuantile[(fi * nSamp) + q];
902 if (curSampleRedundancy > worstRedundancy) {
903 worstRedundancy = curSampleRedundancy;
904 worstRedundancyIndex = si;
907 i = worstRedundancyIndex;
912 std::memcpy(oldf.data(), features.data() + (i * nFeat), nFeat *
sizeof(T));
916 clhs.getRandomPoint(p);
917 while (points.contains((((uint64_t) p.
x) << 32) | ((uint64_t) p.
y))) {
918 clhs.getRandomPoint(p);
922 std::memcpy(features.data() + (i * nFeat), p.
p_features, nFeat *
sizeof(T));
925 std::vector<int> oldq(nFeat);
926 std::vector<int> newq(nFeat);
927 for (
int f = 0; f < nFeat; f++) {
931 sampleCountPerQuantile[(f * nSamp) + q]--;
936 sampleCountPerQuantile[(f * nSamp) + q]++;
940 T newObjQ =
clhs.quantileObjectiveFunc(sampleCountPerQuantile);
943 const auto result = oneapi::dal::compute(cor_desc, table);
944 oneapi::dal::row_accessor<const T> acc {result.get_cor_matrix()};
945 for (
int j = 0; j < nFeat; j++) {
946 auto row = acc.pull({j, j + 1});
948 for (
int k = 0; k < nFeat; k++) {
954 T newObjC =
clhs.correlationObjectiveFunc(corr);
956 T newObj = newObjQ + newObjC;
957 T delta = newObj - obj;
959 bool keep =
dist(rng) < std::exp(-1 * delta / temp);
963 points.erase((((uint64_t) x[i]) << 32) | ((uint64_t) y[i]));
964 points.insert((((uint64_t) p.
x) << 32) | ((uint64_t) p.
y));
969 std::memcpy(quantilesOfEachSample.data() + (i * nFeat), newq.data(),
sizeof(
int) * nFeat);
977 for (
int f = 0; f < nFeat; f++) {
978 sampleCountPerQuantile[(f * nSamp) + newq[f]]--;
979 sampleCountPerQuantile[(f * nSamp) + oldq[f]]++;
983 reinterpret_cast<void *
>(features.data() + (i * nFeat)),
984 reinterpret_cast<void *
>(oldf.data()),
995 for (
int i = starti ; i < nSamp; i++) {
997 OGRPoint point = OGRPoint(xCoord, yCoord);
1003 xCoords.push_back(xCoord);
1004 yCoords.push_back(yCoord);
1044 std::string layerName,
1050 std::optional<uint64_t> random_state,
1051 std::string tempFolder,
1052 std::string filename)
1061 std::vector<double> xCoords, yCoords;
1063 std::vector<helper::RasterBandMetaData> bands(p_raster->
getBandCount());
1064 for (
int i = 0; i < nFeat; i++) {
1068 bands[i].nan = bands[i].p_band->GetNoDataValue();
1069 bands[i].p_band->GetBlockSize(&bands[i].xBlockSize, &bands[i].yBlockSize);
1073 GDALDriver *p_driver = GetGDALDriverManager()->GetDriverByName(
"MEM");
1075 throw std::runtime_error(
"unable to create output sample dataset driver.");
1077 GDALDataset *p_samples = p_driver->Create(
"", 0, 0, 0, GDT_Unknown,
nullptr);
1079 throw std::runtime_error(
"unable to create output dataset with driver.");
1083 OGRLayer *p_layer = p_samples->CreateLayer(
"samples", p_wrapper->
getSRS(), wkbPoint,
nullptr);
1085 throw std::runtime_error(
"unable to create output dataset layer.");
1096 bands[0].xBlockSize,
1114 xso::xoshiro_4x64_plus rng = random_state ? xso::xoshiro_4x64_plus(*random_state) : xso::xoshiro_4x64_plus();
1128 GDALDataType type = GDT_Float32;
1130 if (band.type == GDT_Float64) {
1136 if (type == GDT_Float64) {
1137 std::vector<std::vector<double>>
quantiles;
1143 readRaster<double>(bands,
clhs,
access,
existing, rand, type,
quantiles,
sizeof(
double), width, height, nFeat, nSamp);
1146 selectSamples<double>(
quantiles,
clhs, rng,
existing, replace, iterations, nSamp, nFeat, p_layer, GT, plot, xCoords, yCoords);
1149 std::vector<std::vector<float>>
quantiles;
1155 readRaster<float>(bands,
clhs,
access,
existing, rand, type,
quantiles,
sizeof(
float), width, height, nFeat, nSamp);
1158 selectSamples<float>(
quantiles,
clhs, rng,
existing, replace, iterations, nSamp, nFeat, p_layer, GT, plot, xCoords, yCoords);
1161 if (filename !=
"") {
1163 p_wrapper->
write(filename);
1165 catch (
const std::exception& e) {
1166 std::cout <<
"Exception thrown trying to write file: " << e.what() << std::endl;
1170 return {{xCoords, yCoords}, p_wrapper};