#' Solver for multinomial logit type problems, using only prior module projections
#'
#' @param targets A dataframe with columns lu.from, lu.to and value (all targets will be ignored)
#' @param areas A dataframe of areas with columns lu.from, ns and value, with all areas >= 0
#' and with sum(areas) >= sum(targets)
#' @param xmat A dataframe of explanatory variables with columns ks and value.
#' @param betas A dataframe of coefficients with columns ks, lu.from, lu.to & value
#' @param restrictions A dataframe with columns ns, lu.from, lu.to and value. Values must be zero or one. If restrictions are one, the MNL function is set to zero
#' @param options A list with solver options. Call \code{\link{downscale_control}} for default options and for more detail.
#'
#' @details Given \code{p} targets matches the projections from an MNL-type model.
#'
#' You should not call this functions directly, call \code{\link{downscale}} instead.
#'
#' Areas correspond to either an areas per pixel (ns), with value or optionally the are of lu.from in a pixel. All areas must be larger The function expects lu.from
#'
#' @return A list containing
#' * \code{out.res} A \code{n x p} matrix of area allocations
#' * \code{out.solver} \code{NULL}, returned for compatibility
#'
#' @export solve_notarget.mnl
#' @import tidyr
#' @import dplyr
#' @import tibble
#'
#' @examples
#' ## A basic example
solve_notarget.mnl = function(targets,areas,xmat,betas,restrictions=NULL,
options = downscale_control()) {
lu.from <- unique(targets$lu.from)
lu.to <- unique(targets$lu.to)
ks = unique(betas$ks)
out.solver <- list()
curr.lu.from <- lu.from[1]
full.out.res = NULL
for(curr.lu.from in lu.from){
err.txt = paste0(curr.lu.from," ",options$err.txt)
# Extract targets
curr.targets = dplyr::filter(targets,lu.from == curr.lu.from)$value
names(curr.targets) <- targets$lu.to[targets$lu.from == curr.lu.from]
curr.lu.to = names(curr.targets)
# Extract betas
curr.betas = dplyr::filter(betas,lu.from == curr.lu.from & lu.to %in% curr.lu.to) %>%
tidyr::pivot_wider(names_from = "lu.to",values_from = "value",id_cols = "ks") %>%
tibble::column_to_rownames(var = "ks")
curr.betas = as.matrix(curr.betas)
# Extract xmat
## IMPORTANT CHECK ORDER OF VARIABLES FIXED
curr.xmat = dplyr::filter(xmat,ks %in% row.names(curr.betas)) %>%
tidyr::pivot_wider(names_from = "ks",values_from = "value",id_cols = "ns") %>%
tibble::column_to_rownames(var = "ns") %>%
dplyr::select(rownames(curr.betas))
curr.xmat = as.matrix(curr.xmat)
# Extract areas
curr.areas = dplyr::filter(areas,lu.from == curr.lu.from)$value
names(curr.areas) <- areas$ns[areas$lu.from == curr.lu.from]
# BUGFIX: MW, order of curr.areas wrong, need to re-arrange based on xmat
if (nrow(curr.xmat) > 0) {
curr.areas = curr.areas[match(rownames(curr.xmat),names(curr.areas))]
}
# Extract restrictions
if (!is.null(restrictions) && any(restrictions$lu.from == curr.lu.from)) {
curr.restrictions = dplyr::filter(restrictions,lu.from == curr.lu.from) %>%
tidyr::pivot_wider(names_from = lu.to,values_from = "value",id_cols = "ns") %>%
tibble::column_to_rownames(var = "ns")
curr.restrictions = curr.restrictions[match(names(curr.areas),row.names(curr.restrictions)),,drop = FALSE]
curr.restrictions = as.matrix(curr.restrictions)
} else {curr.restrictions = NULL}
n = length(curr.areas)
p = length(curr.targets)
k = nrow(curr.betas)
# check restrictions for consistency
if (!is.null(curr.restrictions) & any(colnames(curr.restrictions) %in% names(curr.targets))) {
restr.mat = matrix(0,n,p); colnames(restr.mat) = names(curr.targets)
restr.mat[,colnames(curr.restrictions)] = curr.restrictions
} else {restr.mat = NULL}
# out.res contains downscaled estimates; priors.mu econometric & other priors for estimation
out.res = priors.mu = matrix(0,n,p)
colnames(out.res) = colnames(priors.mu) = names(curr.targets)
# match econometric priors
priors.mu[,colnames(curr.betas)] = curr.xmat %*% curr.betas
# make sure the priors are numerically well behaved
priors.mu[priors.mu > options$MAX_EXP] = options$MAX_EXP
priors.mu[priors.mu < -options$MAX_EXP] = -options$MAX_EXP
priors.mu[,colnames(curr.betas)] = exp(priors.mu[,colnames(curr.betas)])
out.mu = mu.mnl(rep(1,p),priors.mu,curr.areas,restr.mat,options$cutoff)
out.res = out.mu
# add residual own flows in output
out.res2 = data.frame(ns = names(curr.areas),
curr.areas - rowSums(out.res),out.res)
colnames(out.res2)[2] = paste0(curr.lu.from)
# pivot into long format
res.agg <- out.res2 %>%
pivot_longer(cols = -c("ns"),names_to = "lu.to") %>%
bind_cols(lu.from = curr.lu.from)
# aggregate results over dataframes
if(curr.lu.from==lu.from[1]){
full.out.res <- res.agg
} else {
full.out.res = bind_rows(full.out.res,res.agg)
}
}
return(list(out.res = full.out.res, out.solver = NULL))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.