## costs-class ####
#' @title An S4 class to add costs to objective function
#' @name class-costs
#'
#' @inherit newCosts description
#'
#' `r lifecycle::badge("experimental")`
#'
#' @md
#' @slot name `r get_slot_info("costs", "name")`
#' @slot desc `r get_slot_info("costs", "desc")`
#' @slot variable `r get_slot_info("costs", "variable")`
#' @slot subset `r get_slot_info("costs", "subset")`
#' @slot mult `r get_slot_info("costs", "mult")`
#' @slot misc `r get_slot_info("costs", "misc")`
#'
#' @include class-constraint.R
#' @family class constraint policy
#' @rdname class-costs
#' @export
setClass("costs",
representation(
name = "character",
desc = "character", # desc
variable = "character",
subset = "data.frame",
mult = "data.frame",
misc = "list"
# parameter= list() # For the future
),
prototype(
name = NULL,
desc = "", # desc
variable = character(),
subset = data.frame(),
mult = data.frame(),
# ! Misc
misc = list()
),
S3methods = FALSE
)
setMethod("initialize", "costs", function(.Object, ...) {
.Object
})
## constructor function ####
#' @title Create new costs object
#'
#' @description Costs object is used to define
#' additional costs to add to the model's
#' objective function.
#'
#' @md
#' @param name `get_slot_info("costs", "name")`
#'
#' @param variable `get_slot_info("costs", "variable")`
#' @param desc `get_slot_info("costs", "desc")`
#' @param mult `get_slot_info("costs", "mult")`
#' @param subset `get_slot_info("costs", "subset")`
#'
#' @return costs object with given specifications.
#' @family class constraint policy
#' @rdname newCosts
#'
#' @export
#'
newCosts <- function(
name,
variable,
desc = "",
mult = NULL,
subset = NULL,
misc = NULL
) {
# browser()
obj <- new("costs")
obj@name <- name
obj@desc <- desc
# Add variable
sets <- .variable_set[[variable]]
if (is.null(sets)) {
stop(paste0('There are unknown variable "', variable, '" in cost "', name,
'".'))
}
# if (anyDuplicated(sets))
# stop(paste0('Add cost to variable with duplicated sets is not allowed now (cost "', name, '").'))
if (anyDuplicated(sets)) {
sets[duplicated(sets)] <- paste0(sets[duplicated(sets)], 2)
}
if (sum(sets %in% c("region", "year")) != 2) {
stop(paste0(
"The cost-object accepts variables with 'region' and 'year' dimensions.\n",
" the variable '", variable, "' has the following sets: ",
paste0(sets, collapse = ", ")))
}
obj@variable <- variable
# Add subset
if (!is.null(subset)) {
if (is.list(subset) && !is.data.frame(subset)) {
subset2 <- data.frame(stringsAsFactors = FALSE)
for (i in names(subset)) {
if (!is.null(subset[[i]])) {
subset2[[i]] <- subset[[i]]
}
}
subset <- subset2
}
if (!all(colnames(subset) %in% sets)) {
bug <- colnames(subset)[!(colnames(subset) %in% sets)]
stop(paste0(
# "There ", c("is", "are")[1 + length(bug) != 1],
"Unrecognized column",
"s"[length(bug) != 1], ' "', paste0(bug, collapse = '", "'),
'" in subset (cost "', name, '").'
))
}
if (!is.data.frame(subset)) {
stop(paste0('Subset must be a list or data.frame (cost "', name, '").'))
}
if (anyDuplicated(subset)) {
stop(paste0('Duplicated row(s) in subset (cost "', name, '").'))
}
subset <- subset[, !apply(is.na(subset), 2, all), drop = FALSE]
obj@subset <- subset
}
# Add mult
if (!is.null(mult)) {
if (!is.data.frame(mult) && !is.numeric(mult)) {
stop(paste0('Mult must be numeric or data.frame (cost "', name, '").'))
}
if (is.numeric(mult)) {
obj@mult <- data.frame(value = mult)
} else {
if (!all(colnames(mult) %in% c("value", sets))) {
bug <- colnames(mult)[!(colnames(mult) %in% c("value", sets))]
stop(paste0(
# "There ", c("is", "are")[1 + length(bug) != 1],
"Unrecognized column",
"s"[length(bug) != 1], ' "', paste0(bug, collapse = '", "'),
'" in mult (cost "', name, '").'
))
}
mult <- mult[, !apply(is.na(mult), 2, all), drop = FALSE]
# if (anyDuplicated(mult[, colnames(mult) != "value", drop = FALSE])) {
if (anyDuplicated(select(mult, -value))) {
stop(paste0('Duplicated row(s) in mult (cost "', name, '").'))
}
if (is.null(mult$value) || any(is.na(mult$value))) {
stop(paste0('NAs in mult (cost "', name, '").'))
}
# Remove unused set values from mult (by subset)
if (any(colnames(mult) %in% colnames(subset))) {
for (ss in colnames(mult)[colnames(mult) %in% colnames(subset)]) {
mult <- mult[is.na(mult[[ss]]) | mult[[ss]] %in%
unique(subset[[ss]][!is.na(subset[[ss]])]), , drop = FALSE]
}
}
if (ncol(mult) > 1) obj@mult <- mult else obj@defVal <- mult$value
}
}
if (nrow(obj@mult) == 0 && obj@defVal == 0) {
warning(paste0('The cost constraint of the "', name, '" is strictly equal to zero.'))
}
obj@misc <- misc
obj
}
## internal functions ####
# Check if the constraint needs additional set(s), add if needed
.getCostEquation <- function(prec, stm, approxim) {
# browser()
stop.constr <- function(x) {
stop(paste0('Cost "', stm@name, '" error: ', x))
}
get.all.child <- function(x) {
unique(c(x, c(approxim$calendar@slice_ancestry[
approxim$calendar@slice_ancestry$parent %in% x, "child"])))
}
have.all.set <- function(x, name) {
return(any(is.na(x)) || (name != "slice" && all(approxim[[name]] %in% x)))
}
sets <- .variable_set[[stm@variable]]
if (anyDuplicated(.variable_set[[stm@variable]])) {
dsets <- sets[duplicated(sets)]
for (dst in dsets) {
approxim[[paste0(dst, 2)]] <- approxim[[dst]]
}
sets[duplicated(sets)] <- paste0(sets[duplicated(sets)], 2)
}
# Generate mult
if (nrow(stm@mult) != 0) {
# browser()
approxim2 <- approxim[
unique(c(colnames(stm@mult)[colnames(stm@mult) %in% names(approxim)],
"fullsets", "solver", "year"))]
if (!is.null(approxim2$slice)) approxim2$slice <- approxim2$calendar@slice_share$slice
if (!is.null(approxim2$slice2)) {
# approxim2$slice2 <- approxim2$slice@all__slice2 #???
browser()
approxim2$slice2 <- approxim2$calendar@slice_share$slice #???
}
if (nrow(stm@subset) != 0) {
same <- colnames(stm@subset)[colnames(stm@subset) %in% colnames(stm@mult)]
same <- same[!apply(is.na(stm@subset[, same, drop = FALSE]), 2, any)]
for (ss in same) {
approxim2[[ss]] <- unique(stm@subset[[ss]][!is.na(stm@subset[[ss]])])
}
}
mult_sets <- colnames(stm@mult)[colnames(stm@mult) != "value"]
for (ss in mult_sets) {
stm@mult <- stm@mult[stm@mult[[ss]] %in% approxim2[[ss]], , drop = FALSE]
}
xx <- newParameter(paste0("pCosts", stm@name), mult_sets, "numpar",
defVal = 0,
interpolation = "back.inter.forth", colName = "value"
)
yy <- .interp_numpar(stm@mult, "value", xx, approxim2)
prec@parameters[[xx@name]] <- .dat2par(xx, yy)
sss <- ""
if (length(mult_sets) != 0) sss <- paste0("(", paste0(mult_sets,
collapse = ", "),
")")
mult_txt <- paste0(xx@name, sss, " * ")
} else {
mult_txt <- paste0(stm@defVal, " * ")
}
# Generate subset
if (nrow(stm@subset) != 0) {
fl <- apply(!is.na(stm@subset), 1, all)
subset <- stm@subset[fl, , drop = FALSE]
approxim2 <- approxim[colnames(stm@subset)]
if (!is.null(approxim2$slice)) approxim2$slice <- approxim2$calendar@slice_share$slice
if (any(!fl)) {
subset_na <- stm@subset[!fl, , drop = FALSE]
for (i in seq_len(ncol(subset_na))[apply(is.na(subset_na), 2, any)]) {
f2 <- is.na(subset_na[[i]])
subset_na2 <- subset_na[fl, , drop = FALSE]
subset_na3 <- subset_na2[0, , drop = FALSE]
ncs <- approxim2[[colnames(subset_na)[i]]]
subset_na3[nrow(subset_na2) * length(ncs), ] <- NA
for (j in seq_len(ncol(subset_na))[seq_len(ncol(subset_na)) != i]) {
subset_na3[, j] <- subset_na3[[j]]
}
subset_na3[, j] <- c(matrix(ncs, nrow(subset_na3), length(ncs), byrow = TRUE))
subset_na <- unique(rbind(subset_na[!fl, , drop = FALSE], subset_na3))
}
subset <- rbind(subset, subset_na)
}
for (ss in colnames(subset)) {
subset <- subset[subset[[ss]] %in% approxim2[[ss]], , drop = FALSE]
}
xnm <- paste0("mCosts", stm@name)
prec@parameters[[xnm]] <- .dat2par(newParameter(xnm, colnames(subset), "map"),
subset)
subset_txt <- paste0(xnm, "(", paste0(colnames(subset), collapse = ", "), ")")
} else {
subset_txt <- NULL
}
# Generate equation text
mps <- .variable_mapping[[stm@variable]]
if (length(sets) == 2) {
if (is.null(subset_txt)) {
costs <- paste0(mult_txt, mps)
} else if (any(grep("[$]", mps))) {
costs <- paste0(
"(", mult_txt, gsub("[$].*", "", mps), ")$(", gsub(".*[$]", "", mps),
" and ", subset_txt, ")"
)
} else {
costs <- paste0("(", mult_txt, mps, "$", subset_txt)
}
} else {
nset <- sets[!(sets %in% c("region", "year"))]
if (length(nset) != 1) nset <- paste0("(", paste0(nset, collapse = ", "), ")")
mps <- gsub("[(][^(]*[)]", paste0("( ", paste0(sets, collapse = " , "), " )"), mps)
nkk <- c(gsub(".*[$]", "", mps), subset_txt)
if (length(nkk) != 1) nkk <- paste0("(", paste0(nkk, collapse = " and "), ")")
costs <- paste0("sum(", nset, "$", nkk, ", ", mult_txt, gsub("[$].*", "", mps), ")")
}
costs <- gsub("[ ]*[*][ ]*", " * ", gsub("[)]and", ") and", gsub("[ ]*[,][ ]*", ", ", gsub(
"[ ]*[)][ ]*", ")",
gsub("[ ]*[(][ ]*", "(", gsub("[+][ ]*[-]", "-", gsub("[ ]*[$][ ]*", "$", costs)))
))))
prec@costs.equation <- c(prec@costs.equation, costs)
prec
}
# .getSetEquation(prec, stm, approxim)@gams.equation
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.