@@ -74,7 +74,7 @@ interpolate_convex_hull = function(points, ch_halfspace, n_samples_per_dimension
74
74
# ' the model terms, weighted by whether the point
75
75
# ' is on the edge.
76
76
# '
77
- # ' @param data Candidate set
77
+ # ' @param candidate_set_full Candidate set
78
78
# ' @param formula Default `~ .`. Model formula specifying the terms.
79
79
# ' @param n_samples_per_dimension Default `100`. Number of samples to take per dimension when interpolating inside
80
80
# ' the convex hull.
@@ -99,17 +99,28 @@ gen_momentsmatrix_continuous = function(
99
99
# Detect any disallowed combinations
100
100
unique_vals = prod(vapply(candidate_set , \(x ) {length(unique(x ))}, FUN.VALUE = integer(1 )))
101
101
any_disallowed = unique_vals != nrow(candidate_set )
102
+ M_acc = NA
103
+ total_weight = 0
102
104
103
105
# Simple if all numeric: just integrate over the region.
104
106
if (length(factor_cols ) == 0 ) {
105
107
sub_candidate_set = as.matrix(candidate_set )
106
- ch = convhull_halfspace(sub_candidate_set )
107
- if (ch $ volume < = 0 ) {
108
- next
108
+ if (ncol(sub_candidate_set ) == 1 ) {
109
+ new_pts_ch = matrix (seq(min(sub_candidate_set ),
110
+ max(sub_candidate_set ),
111
+ length.out = n_samples_per_dimension ),ncol = 1 )
112
+ interp_ch = list ()
113
+ interp_ch $ on_edge = rep(FALSE , nrow(new_pts_ch ))
114
+ vol = max(sub_candidate_set ) - min(sub_candidate_set )
115
+ } else {
116
+ ch = convhull_halfspace(sub_candidate_set )
117
+ if (ch $ volume < = 0 ) {
118
+ next
119
+ }
120
+ vol = ch $ volume
121
+ interp_ch = interpolate_convex_hull(as.matrix(sub_candidate_set ), ch , n_samples_per_dimension = n_samples_per_dimension )
122
+ new_pts_ch = interp_ch $ data
109
123
}
110
- vol = ch $ volume
111
- interp_ch = interpolate_convex_hull(as.matrix(sub_candidate_set ), ch , n_samples_per_dimension = n_samples_per_dimension )
112
- new_pts_ch = interp_ch $ data
113
124
114
125
colnames(new_pts_ch ) = numeric_cols
115
126
interp_df = as.data.frame(new_pts_ch )
@@ -121,23 +132,16 @@ gen_momentsmatrix_continuous = function(
121
132
w [interp_ch $ on_edge ] = 0.5
122
133
# average subregion moment
123
134
Xsub_w = apply(Xsub ,2 ,\(x ) x * sqrt(w ))
124
- # M_sub = crossprod(Xsub) / sum(w)
125
135
126
- M_sub = crossprod(Xsub_w ) / sum(w )
136
+ M = crossprod(Xsub_w ) / sum(w )
127
137
128
- # Weighted accumulation
129
- if (is.null(M_acc )) {
130
- M_acc = vol * M_sub
131
- } else {
132
- M_acc = M_acc + vol * M_sub
133
- }
134
- total_weight = total_weight + vol
135
138
# Scale by the intercept
136
139
if (colnames(M )[1 ] == " (Intercept)" ) {
137
140
M = M / M [1 ,1 ]
138
141
}
139
142
return (M )
140
143
} else {
144
+ M_acc = NA
141
145
# For categorical factors with disallowed combinations, we need to account for the
142
146
# reduced domain of the integral. We'll calculate a moment matrix as above for each
143
147
# factor level combination, weigh it by the total number of points, and sum it. That
@@ -155,7 +159,6 @@ gen_momentsmatrix_continuous = function(
155
159
}
156
160
157
161
# We'll accumulate a weighted sum of sub-matrices
158
- M_acc = NULL
159
162
total_weight = 0
160
163
161
164
for (r in seq_len(nrow(unique_combos ))) {
@@ -167,20 +170,28 @@ gen_momentsmatrix_continuous = function(
167
170
is_match = is_match & (candidate_set [[fc ]] == combo_row [[fc ]])
168
171
}
169
172
sub_candidate_set = candidate_set [is_match , , drop = FALSE ]
170
- sub_candidate_set = sub_candidate_set [,is_numeric_col ]
173
+ sub_candidate_set = sub_candidate_set [,is_numeric_col , drop = FALSE ]
171
174
# If no rows => disallowed or doesn't appear => skip
172
- if (! nrow(sub_candidate_set )) {
175
+ if (nrow(sub_candidate_set ) == 0 ) {
173
176
next
174
177
}
175
-
176
- # Calculate the convex hull and sample points
177
- ch = convhull_halfspace(sub_candidate_set )
178
- if (ch $ volume < = 0 ) {
179
- next
178
+ if (ncol(sub_candidate_set ) == 1 ) {
179
+ new_pts_ch = matrix (seq(min(sub_candidate_set ),
180
+ max(sub_candidate_set ),
181
+ length.out = n_samples_per_dimension ),ncol = 1 )
182
+ interp_ch = list ()
183
+ interp_ch $ on_edge = rep(FALSE , nrow(new_pts_ch ))
184
+ vol = max(sub_candidate_set ) - min(sub_candidate_set )
185
+ } else {
186
+ ch = convhull_halfspace(sub_candidate_set )
187
+ if (ch $ volume < = 0 ) {
188
+ next
189
+ }
190
+ vol = ch $ volume
191
+ interp_ch = interpolate_convex_hull(as.matrix(sub_candidate_set ), ch ,
192
+ n_samples_per_dimension = n_samples_per_dimension )
193
+ new_pts_ch = interp_ch $ data
180
194
}
181
- vol = ch $ volume
182
- interp_ch = interpolate_convex_hull(as.matrix(sub_candidate_set ), ch , n_samples_per_dimension = n_samples_per_dimension )
183
- new_pts_ch = interp_ch $ data
184
195
185
196
colnames(new_pts_ch ) = numeric_cols
186
197
interp_df = as.data.frame(new_pts_ch )
@@ -191,7 +202,8 @@ gen_momentsmatrix_continuous = function(
191
202
}
192
203
193
204
# Now build model matrix
194
- Xsub = model.matrix(formula , data = interp_df , contrasts.arg = get_contrasts_from_candset(candidate_set ))
205
+ Xsub = model.matrix(formula , data = interp_df ,
206
+ contrasts.arg = get_contrasts_from_candset(candidate_set ))
195
207
196
208
w = rep(1 , nrow(Xsub ))
197
209
w [interp_ch $ on_edge ] = 0.5
@@ -202,7 +214,7 @@ gen_momentsmatrix_continuous = function(
202
214
M_sub = crossprod(Xsub_w ) / sum(w )
203
215
204
216
# Weighted accumulation
205
- if (is.null (M_acc )) {
217
+ if (all( is.na (M_acc ) )) {
206
218
M_acc = vol * M_sub
207
219
} else {
208
220
M_acc = M_acc + vol * M_sub
0 commit comments