Skip to content

Commit

Permalink
Proposal lookup API now allows Init*ErgmProposal.*() functions to ret…
Browse files Browse the repository at this point in the history
…urn NULL, in which case the next eligible proposal down the list will be used. Specificly:

* select_ergm_proposal() is now select_ergm_proposals(), returning a data frame of eligible proposals sorted by score in descending order.
* ergm_proposal.ergm_conlist() now loops through the eligible proposals until one is not NULL.
* ergm_proposal.character() now returns NULL if the Init*ErgmProposal.*() returned NULL.

references #456
  • Loading branch information
krivit committed Oct 11, 2023
1 parent 2fef2ff commit 10e0c47
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 10 deletions.
27 changes: 18 additions & 9 deletions R/ergm_proposal.R
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ ergm_proposal.character <- function(object, arguments, nw, ..., reference=ergm_r
}else as.call(list(f, arguments, nw))

proposal <- eval(prop.call)
if(is.null(proposal)) return(NULL)

storage.mode(proposal$inputs) <- "double"
storage.mode(proposal$iinputs) <- "integer"
Expand Down Expand Up @@ -326,7 +327,7 @@ c.ergm_conlist <- function(...) NextMethod() %>% prune.ergm_conlist()
structure(NextMethod(), class = "ergm_conlist")
}

select_ergm_proposal <- function(conlist, class, ref, weights){
select_ergm_proposals <- function(conlist, class, ref, weights){
# Extract directly selected proposal, if given, check that it's unique, and discard its constraint and other placeholders.
name <- conlist %>% .keep_constraint(".select") %>% map_chr("proposal") %>% unique()
if(length(name) > 1) stop("Error in direct proposal selection: two distinct proposals selected: ", paste.and(sQuote(name)), ".", call.=FALSE)
Expand Down Expand Up @@ -391,9 +392,7 @@ select_ergm_proposal <- function(conlist, class, ref, weights){
stop("The combination of class (",class,"), model constraints and hints (",paste.and(sQuote(unique(names(conlist)))),"), reference measure (",deparse(ult(ref$name)),"), proposal weighting (",weights,"), and conjunctions and disjunctions is not implemented. ", "Check your arguments for typos. ")
}

proposal <- qualifying[which.max(qualifying$Score),]
if(proposal$Unmet!="") message("Best valid proposal ", sQuote(proposal$Proposal), " cannot take into account hint(s) ", proposal$Unmet, ".")
proposal
qualifying[order(qualifying$Score, decreasing=TRUE),]
}

ergm_reference <- function(object, ...) UseMethod("ergm_reference")
Expand Down Expand Up @@ -454,11 +453,21 @@ ergm_proposal.term_list <- ergm_proposal.formula
#' @export
ergm_proposal.ergm_conlist <- function(object, arguments, nw, weights="default", class="c", reference=trim_env(~Bernoulli), ..., term.options=list()) {
reference <- ergm_reference(reference, nw, term.options=term.options, ...)
proposal <- select_ergm_proposal(object, class = class, ref = reference, weights = weights)
name <- proposal$Proposal
arguments$constraints <- object
## Hand it off to the class character method.
ergm_proposal(name, arguments, nw, reference = reference, ..., term.options = term.options)
proposals <- select_ergm_proposals(object, class = class, ref = reference, weights = weights)

for(i in seq_len(nrow(proposals))){
proposal <- proposals[i,]
name <- proposal$Proposal
arguments$constraints <- object
## Hand it off to the class character method.
proposal <- ergm_proposal(name, arguments, nw, reference = reference, ..., term.options = term.options)

## Keep trying until some proposal function accepts.
if(!is.null(proposal)) break
}

if(proposals[i,]$Unmet!="") message("Best valid proposal ", sQuote(proposals[i,]$Proposal), " cannot take into account hint(s) ", proposals[i,]$Unmet, ".")
proposal
}

########################################################################################
Expand Down
3 changes: 2 additions & 1 deletion vignettes/Proposal-Lookup-API.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ Most of this is implemented in the `ergm_proposal.formula()` method:
1. If a proposal cannot enforce a constraint that is among the requested with `priority==Inf`, it is discarded.
1. For each constraint that is among requested with `priority<Inf` *and* that the proposal **does**n't and **can**'t enforce, its (innate, specified in the column of the `ergm_proposal_table()`) `Priority` value is penalised by the `priority` of that constraint.
1. If there are no candidate proposals left, an error is raised.
1. If more than one is left, the proposal with the highest priority (after being penalised for unmet constraints) is selected.
1. If more than one is left,
1. Calls to `InitErgmProposal.*` functions are attempted. If a call returns `NULL`, next proposal is attempted. (This can be useful if a proposal handles a particular special case that is not accounted for by constraints.)

0 comments on commit 10e0c47

Please sign in to comment.