Feature: CLUMPY style allocation#30
Conversation
…architecture Agent-Logs-Url: https://github.com/ethzplus/evoland-plus/sessions/39b6065d-0375-4ce9-ae25-40e65e2e68dd Co-authored-by: mmyrte <[email protected]>
…lock Agent-Logs-Url: https://github.com/ethzplus/evoland-plus/sessions/39b6065d-0375-4ce9-ae25-40e65e2e68dd Co-authored-by: mmyrte <[email protected]>
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
air
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_alloc_params_t.R
Lines 79 to 80 in 2cfdcba
[air] reported by reviewdog 🐶
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_trans_pot_t.R
Lines 11 to 12 in 2cfdcba
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_trans_pot_t.R
Lines 37 to 38 in 2cfdcba
[air] reported by reviewdog 🐶
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_trans_pot_t.R
Lines 43 to 44 in 2cfdcba
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_trans_pot_t.R
Lines 48 to 49 in 2cfdcba
[air] reported by reviewdog 🐶
evoland-plus/inst/tinytest/test_trans_pot_t.R
Lines 81 to 82 in 2cfdcba
6a135de to
a672f32
Compare
…esis Adds dev/pivot-mechanism-verification.md documenting: - GART/MuST pivot test is a faithful inverse-CDF translation - the allocator implements the simplified single-pass strategy, not the bias-free uPAM (no per-patch P(v|u) update, no merge rollback) - the 1/E(sigma) pivot rarefaction (thesis Fig. 3.2) is missing - determinism behaviour under 0/1 transition potentials Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
…hape metric
Move the whole CLUMPY pivot-selection + patch-growth routine into C++
(allocate_clumpy_cpp) so the hot loop no longer crosses into R per patch.
- Add selectable allocation methods:
* uSAM (single GART pass, quantity of change in expectation)
* uPAM (iterative GART with a per-transition pixel quota and sampling
without replacement; batch_size dials speed vs fidelity, 1 = strict
one-pivot-per-draw). Affordable here because evoland's fixed-model
potentials are pool-independent, so rho(z|u) is never re-estimated.
- Apply the 1/E(sigma) pivot rarefaction before GART (thesis Fig. 3.2) so the
allocated quantity of change matches the target rate; rate confirmed to be a
quantity-of-change rate via get_obs_trans_rates.
- Clamp negative/NaN potentials inside GART (matches reference clumpy).
- Move gart/sample_lognorm_area/raster_neighbors from R into C++
(gart_cpp, sample_lognorm_area_cpp, raster_neighbors_cpp).
- Unify the duplicate patch-shape metric (patch_eccentricity vs
calculate_elongation) into clumpy::elongation_from_raw_moments
(src/clumpy_geometry.h), shared by the grower and calculate_class_stats_cpp.
- Patch grower uses incremental moments (O(1) per candidate) and the shared
metric; thread method/batch_size through alloc_clumpy() and the evoland_db
binding; update unit tests to the C++ entry points.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
…nterface cleanup
- avoid_aggregation (default TRUE for uPAM): deferred-write, all-or-nothing patch
growth that fails (allocating nothing) if a patch would merge with another or
cannot reach its sampled area; attempted cells are removed from the pool
(sampling without replacement). Replicates clumpy's GaussianPatcher.
- Auto-select the method from patch params (all mono-pixel -> uSAM, else uPAM)
instead of a user switch; uSAM is now strictly mono-pixel. The C++ keeps an
explicit method flag for tests/comparison.
- Expose patch-area distribution via area_dist ('lognormal' default, 'normal');
area_var is a variance (normal uses sd = sqrt(area_var)).
- allocate_clumpy_cpp drops ant_landscape (anterior snapshotted internally) and
from_classes (derived from trans_from).
- Rename eccentricity -> elongation everywhere (incl. alloc_params_clumpy_v
column), matching the thesis.
- Update unit + integration tests and RcppExports; extend dev verification note.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
| landscape = land_adj, ant_landscape = ant_adj, probs = probs_adj, | ||
| nbr_above = nbr14$above, nbr_below = nbr14$below, | ||
| nbr_left = nbr14$left, nbr_right = nbr14$right, | ||
| pivot = 1L, target_area = 3L, from_class = 1L, to_class = 2L, | ||
| elongation = 0.0, ncol = 4L, avoid_aggregation = TRUE |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = land_adj, ant_landscape = ant_adj, probs = probs_adj, | |
| nbr_above = nbr14$above, nbr_below = nbr14$below, | |
| nbr_left = nbr14$left, nbr_right = nbr14$right, | |
| pivot = 1L, target_area = 3L, from_class = 1L, to_class = 2L, | |
| elongation = 0.0, ncol = 4L, avoid_aggregation = TRUE | |
| landscape = land_adj, | |
| ant_landscape = ant_adj, | |
| probs = probs_adj, | |
| nbr_above = nbr14$above, | |
| nbr_below = nbr14$below, | |
| nbr_left = nbr14$left, | |
| nbr_right = nbr14$right, | |
| pivot = 1L, | |
| target_area = 3L, | |
| from_class = 1L, | |
| to_class = 2L, | |
| elongation = 0.0, | |
| ncol = 4L, | |
| avoid_aggregation = TRUE |
| landscape = land_adj2, ant_landscape = ant_adj, probs = probs_adj, | ||
| nbr_above = nbr14$above, nbr_below = nbr14$below, | ||
| nbr_left = nbr14$left, nbr_right = nbr14$right, | ||
| pivot = 1L, target_area = 3L, from_class = 1L, to_class = 2L, | ||
| elongation = 0.0, ncol = 4L, avoid_aggregation = FALSE |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = land_adj2, ant_landscape = ant_adj, probs = probs_adj, | |
| nbr_above = nbr14$above, nbr_below = nbr14$below, | |
| nbr_left = nbr14$left, nbr_right = nbr14$right, | |
| pivot = 1L, target_area = 3L, from_class = 1L, to_class = 2L, | |
| elongation = 0.0, ncol = 4L, avoid_aggregation = FALSE | |
| landscape = land_adj2, | |
| ant_landscape = ant_adj, | |
| probs = probs_adj, | |
| nbr_above = nbr14$above, | |
| nbr_below = nbr14$below, | |
| nbr_left = nbr14$left, | |
| nbr_right = nbr14$right, | |
| pivot = 1L, | |
| target_area = 3L, | |
| from_class = 1L, | |
| to_class = 2L, | |
| elongation = 0.0, | |
| ncol = 4L, | |
| avoid_aggregation = FALSE |
The thesis only uses the 'Multinomial Sampling Test (MuST)' name (Mazy App. 3.B); 'GART'/'generalized allocation rejection test' is local to the clumpy codebase, and 'rejection test' in the thesis refers only to Dinamica EGO's distinct two-stage process. What clumpy's GART computes is exactly MuST, so: - export the pivot test as must_cpp (was gart_cpp); rename the internal must_draw_one helper and all GART comments/docs to MuST. - the docstring notes the clumpy GART correspondence. - update RcppExports, unit tests, and R-layer docs accordingly. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
…place For large rasters (8M+ cells) the dense n_cells x T potential matrix is the dominant memory cost. Pass the adjusted potentials as per-transition sparse R lists (prob_cell / prob_value) instead, and store them in C++ as SparseColumn (sorted cell indices + values, O(log nnz) lookup, ~12 B/nonzero). The grower is templated on a probability accessor so both the sparse allocator and the dense grow_patch_cpp test primitive share one implementation. Also: remove the now-unused shuffle_in_place (uSAM is mono-pixel/order-free; uPAM uses shuffle_pair); add a comment that cell indices are int (R 32-bit, caps rasters at ~2.1e9 cells). Update RcppExports and unit tests; the sparse subset test confirms only cells carrying a potential can transition. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
| is_mono <- all(!is.na(area_mean) & area_mean == 1 & | ||
| (is.na(area_var) | area_var == 0)) |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| is_mono <- all(!is.na(area_mean) & area_mean == 1 & | |
| (is.na(area_var) | area_var == 0)) | |
| is_mono <- all(!is.na(area_mean) & area_mean == 1 & (is.na(area_var) | area_var == 0)) |
| landscape = ant, nrow = nr, ncol = nc, | ||
| trans_from = 1L, trans_to = 2L, prob_cell = sp$cell, prob_value = sp$value, | ||
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 0.3, | ||
| method = 0L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | ||
| avoid_aggregation = FALSE, area_dist = 0L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant, nrow = nr, ncol = nc, | |
| trans_from = 1L, trans_to = 2L, prob_cell = sp$cell, prob_value = sp$value, | |
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 0.3, | |
| method = 0L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | |
| avoid_aggregation = FALSE, area_dist = 0L | |
| landscape = ant, | |
| nrow = nr, | |
| ncol = nc, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = sp$cell, | |
| prob_value = sp$value, | |
| area_mean = 1.0, | |
| area_var = 0.0, | |
| elongation = 0.0, | |
| target_rate = 0.3, | |
| method = 0L, | |
| batch_size = 1L, | |
| rarefy = TRUE, | |
| shuffle = TRUE, | |
| avoid_aggregation = FALSE, | |
| area_dist = 0L |
| landscape = ant, nrow = nr, ncol = nc, | ||
| trans_from = 1L, trans_to = 2L, prob_cell = sp$cell, prob_value = sp$value, | ||
| area_mean = 2.0, area_var = 1.0, elongation = 0.0, target_rate = 0.3, | ||
| method = 1L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | ||
| avoid_aggregation = TRUE, area_dist = 0L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant, nrow = nr, ncol = nc, | |
| trans_from = 1L, trans_to = 2L, prob_cell = sp$cell, prob_value = sp$value, | |
| area_mean = 2.0, area_var = 1.0, elongation = 0.0, target_rate = 0.3, | |
| method = 1L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | |
| avoid_aggregation = TRUE, area_dist = 0L | |
| landscape = ant, | |
| nrow = nr, | |
| ncol = nc, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = sp$cell, | |
| prob_value = sp$value, | |
| area_mean = 2.0, | |
| area_var = 1.0, | |
| elongation = 0.0, | |
| target_rate = 0.3, | |
| method = 1L, | |
| batch_size = 1L, | |
| rarefy = TRUE, | |
| shuffle = TRUE, | |
| avoid_aggregation = TRUE, | |
| area_dist = 0L |
| landscape = ant, nrow = nr, ncol = nc, | ||
| trans_from = 1L, trans_to = 2L, prob_cell = sp1$cell, prob_value = sp1$value, | ||
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | ||
| method = 0L, batch_size = 1L, rarefy = FALSE, shuffle = TRUE, | ||
| avoid_aggregation = FALSE, area_dist = 0L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant, nrow = nr, ncol = nc, | |
| trans_from = 1L, trans_to = 2L, prob_cell = sp1$cell, prob_value = sp1$value, | |
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | |
| method = 0L, batch_size = 1L, rarefy = FALSE, shuffle = TRUE, | |
| avoid_aggregation = FALSE, area_dist = 0L | |
| landscape = ant, | |
| nrow = nr, | |
| ncol = nc, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = sp1$cell, | |
| prob_value = sp1$value, | |
| area_mean = 1.0, | |
| area_var = 0.0, | |
| elongation = 0.0, | |
| target_rate = 1.0, | |
| method = 0L, | |
| batch_size = 1L, | |
| rarefy = FALSE, | |
| shuffle = TRUE, | |
| avoid_aggregation = FALSE, | |
| area_dist = 0L |
| landscape = ant, nrow = nr, ncol = nc, | ||
| trans_from = 1L, trans_to = 2L, | ||
| prob_cell = list(integer(0)), prob_value = list(numeric(0)), | ||
| area_mean = 2.0, area_var = 1.0, elongation = 0.0, target_rate = 0.3, | ||
| method = 1L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | ||
| avoid_aggregation = TRUE, area_dist = 0L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant, nrow = nr, ncol = nc, | |
| trans_from = 1L, trans_to = 2L, | |
| prob_cell = list(integer(0)), prob_value = list(numeric(0)), | |
| area_mean = 2.0, area_var = 1.0, elongation = 0.0, target_rate = 0.3, | |
| method = 1L, batch_size = 1L, rarefy = TRUE, shuffle = TRUE, | |
| avoid_aggregation = TRUE, area_dist = 0L | |
| landscape = ant, | |
| nrow = nr, | |
| ncol = nc, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = list(integer(0)), | |
| prob_value = list(numeric(0)), | |
| area_mean = 2.0, | |
| area_var = 1.0, | |
| elongation = 0.0, | |
| target_rate = 0.3, | |
| method = 1L, | |
| batch_size = 1L, | |
| rarefy = TRUE, | |
| shuffle = TRUE, | |
| avoid_aggregation = TRUE, | |
| area_dist = 0L |
The previous big-grid check sum(agg)<=sum(noagg) was not a valid invariant: both runs are quota-bounded uPAM (target_rate), so totals are ~equal not ordered; with avoidance, successful patches are full-size (all-or-nothing) so the last patch overshoots the quota more, and the FP-sensitive greedy growth diverges across compilers/arch (passed on x86/gcc by hitting the quota exactly, failed on arm/clang). Replace with a deterministic 1x5 case (forced potentials, area variance 0, no shuffle) where avoidance unambiguously rejects the middle merging patch: noagg=5, agg=4. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0189ymK6BeCwBC8iZ45CGuVb
| landscape = ant_row, nrow = 1L, ncol = 5L, | ||
| trans_from = 1L, trans_to = 2L, prob_cell = row_cell, prob_value = row_val, | ||
| area_mean = 2.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | ||
| method = 1L, batch_size = 0L, rarefy = FALSE, shuffle = FALSE, | ||
| avoid_aggregation = agg, area_dist = 1L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant_row, nrow = 1L, ncol = 5L, | |
| trans_from = 1L, trans_to = 2L, prob_cell = row_cell, prob_value = row_val, | |
| area_mean = 2.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | |
| method = 1L, batch_size = 0L, rarefy = FALSE, shuffle = FALSE, | |
| avoid_aggregation = agg, area_dist = 1L | |
| landscape = ant_row, | |
| nrow = 1L, | |
| ncol = 5L, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = row_cell, | |
| prob_value = row_val, | |
| area_mean = 2.0, | |
| area_var = 0.0, | |
| elongation = 0.0, | |
| target_rate = 1.0, | |
| method = 1L, | |
| batch_size = 0L, | |
| rarefy = FALSE, | |
| shuffle = FALSE, | |
| avoid_aggregation = agg, | |
| area_dist = 1L |
| landscape = ant, nrow = nr, ncol = nc, | ||
| trans_from = 1L, trans_to = 2L, | ||
| prob_cell = list(some_cells), prob_value = list(rep(1.0, length(some_cells))), | ||
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | ||
| method = 0L, batch_size = 1L, rarefy = FALSE, shuffle = TRUE, | ||
| avoid_aggregation = FALSE, area_dist = 0L |
There was a problem hiding this comment.
[air] reported by reviewdog 🐶
| landscape = ant, nrow = nr, ncol = nc, | |
| trans_from = 1L, trans_to = 2L, | |
| prob_cell = list(some_cells), prob_value = list(rep(1.0, length(some_cells))), | |
| area_mean = 1.0, area_var = 0.0, elongation = 0.0, target_rate = 1.0, | |
| method = 0L, batch_size = 1L, rarefy = FALSE, shuffle = TRUE, | |
| avoid_aggregation = FALSE, area_dist = 0L | |
| landscape = ant, | |
| nrow = nr, | |
| ncol = nc, | |
| trans_from = 1L, | |
| trans_to = 2L, | |
| prob_cell = list(some_cells), | |
| prob_value = list(rep(1.0, length(some_cells))), | |
| area_mean = 1.0, | |
| area_var = 0.0, | |
| elongation = 0.0, | |
| target_rate = 1.0, | |
| method = 0L, | |
| batch_size = 1L, | |
| rarefy = FALSE, | |
| shuffle = TRUE, | |
| avoid_aggregation = FALSE, | |
| area_dist = 0L |
R CMD check (light) failed during package load because
evoland_db_views.Rattempted to add public methods that are now already declared inevoland_db.R. The failure was caused by duplicate R6 method registration at load time.R6 method override compatibility
evoland_db$set(...)calls inR/evoland_db_views.Rto explicitly allow replacing predeclared methods:trans_rates_dinamica_vadjusted_trans_pot_valloc_params_clumpy_vevoland_db.Ras the canonical method declaration surface while preserving view-backed implementations inevoland_db_views.R.Behavioral impact