diff --git a/DESCRIPTION b/DESCRIPTION index f0e5690..12e7a0f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: mpoly Type: Package Title: Symbolic Computation and More with Multivariate Polynomials -Version: 1.1.1.901 +Version: 1.1.1.902 URL: https://github.com/dkahle/mpoly BugReports: https://github.com/dkahle/mpoly/issues Authors@R: person("David", "Kahle", email = "david@kahle.io", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9999-1558")) diff --git a/NAMESPACE b/NAMESPACE index 9ee275a..a6b6b06 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -69,6 +69,7 @@ export(mp) export(mpoly) export(mpolyList) export(multideg) +export(normalize_coefficients) export(partitions) export(permutations) export(plug) diff --git a/NEWS.md b/NEWS.md index 4d6e6c4..222cb8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,11 @@ * `coef()` allows you to extract the coefficients of an mpoly object (#25, thanks @ggrothendieck). + +* `deriv()` now allows you to not bring the power down as a multiplier. + +* `normalize_coefficients()` now allows you normalize term coefficients + according to an input norm, defaulting to the Euclidean norm. diff --git a/R/components.R b/R/components.R index 0a7795a..2c4b36f 100644 --- a/R/components.R +++ b/R/components.R @@ -11,6 +11,9 @@ #' @param object mpoly object to pass to [coef()] #' @param ... In [coef()], additional arguments passed to [print.mpoly()] for #' the names of the resulting vector +#' @param p an object of class mpoly or mpolyList +#' @param norm a norm (function) to normalize the coefficients of a polynomial, +#' defaults to the Euclidean norm #' @return An object of class mpoly or mpolyList, depending on the context #' @name components #' @examples @@ -35,6 +38,18 @@ #' #' homogeneous_components(p) #' +#' (p <- mp("(x + y)^2")) +#' normalize_coefficients(p) +#' norm <- function(v) sqrt(sum(v^2)) +#' norm(coef( normalize_coefficients(p) )) +#' +#' abs_norm <- function(x) sum(abs(x)) +#' normalize_coefficients(p, norm = abs_norm) +#' +#' p <- mp(c("x", "2 y")) +#' normalize_coefficients(p) +#' +#' @@ -174,3 +189,16 @@ coef.mpoly <- function(object, ...) { + + +#' @rdname components +#' @export +normalize_coefficients <- function(p, norm = function(x) sqrt(sum(x^2))) { + if (is.mpolyList(p)) return( structure(lapply(p, normalize_coefficients), class = "mpolyList") ) + normalize <- function(x) x / norm(x) + c <- normalize(coef(p)) + for (i in seq_along(p)) p[[i]]["coef"] <- c[i] + p +} + + diff --git a/R/deriv.mpoly.R b/R/deriv.mpoly.R index 74e0135..9a303f1 100644 --- a/R/deriv.mpoly.R +++ b/R/deriv.mpoly.R @@ -6,18 +6,25 @@ #' @param expr an object of class mpoly #' @param var character - the partial derivative desired #' @param ... any additional arguments +#' @param bring_power_down if `FALSE`, x^n -> x^(n-1), not n x^(n-1) #' @return An object of class mpoly or mpolyList. #' @export #' @examples -#' m <- mp("x y + y z + z^2") -#' deriv(m, "x") -#' deriv(m, "y") -#' deriv(m, "z") -#' deriv(m, c("x","y","z")) -#' deriv(m, "a") -#' is.mpoly(deriv(m, "x")) -#' is.mpolyList( deriv(m, c("x","y","z")) ) -deriv.mpoly <- function(expr, var, ...){ +#' p <- mp("x y + y z + z^2") +#' deriv(p, "x") +#' deriv(p, "y") +#' deriv(p, "z") +#' deriv(p, "t") +#' deriv(p, c("x","y","z")) +#' +#' is.mpoly(deriv(p, "x")) +#' is.mpolyList( deriv(p, c("x","y","z")) ) +#' +#' p <- mp("x^5") +#' deriv(p, "x") +#' deriv(p, "x", bring_power_down = FALSE) +#' +deriv.mpoly <- function(expr, var, ..., bring_power_down = TRUE){ # argument checks if (missing(var)) stop("var must be specified, see ?deriv.mpoly", call. = FALSE) @@ -46,7 +53,7 @@ deriv.mpoly <- function(expr, var, ...){ if(length(v) == 1) return(c(coef = 0)) p <- length(v) if(!(var %in% names(v[1:p]))) return(c(coef = 0)) - v["coef"] <- unname(v[var]) * v["coef"] + if (bring_power_down) v["coef"] <- unname(v[var]) * v["coef"] v[var] <- v[var] - 1 v }) diff --git a/man/components.Rd b/man/components.Rd index e4ac4b3..1198d2d 100644 --- a/man/components.Rd +++ b/man/components.Rd @@ -11,6 +11,7 @@ \alias{monomials} \alias{exponents} \alias{coef.mpoly} +\alias{normalize_coefficients} \title{Polynomial components} \usage{ \method{[}{mpoly}(x, ndx) @@ -30,6 +31,8 @@ monomials(x, unit = FALSE) exponents(x, reduced = FALSE) \method{coef}{mpoly}(object, ...) + +normalize_coefficients(p, norm = function(x) sqrt(sum(x^2))) } \arguments{ \item{x}{an object of class mpoly} @@ -48,6 +51,11 @@ exponents(x, reduced = FALSE) \item{...}{In \code{\link[=coef]{coef()}}, additional arguments passed to \code{\link[=print.mpoly]{print.mpoly()}} for the names of the resulting vector} + +\item{p}{an object of class mpoly or mpolyList} + +\item{norm}{a norm (function) to normalize the coefficients of a polynomial, +defaults to the Euclidean norm} } \value{ An object of class mpoly or mpolyList, depending on the context @@ -77,4 +85,16 @@ lapply(exponents(p), is.integer) homogeneous_components(p) +(p <- mp("(x + y)^2")) +normalize_coefficients(p) +norm <- function(v) sqrt(sum(v^2)) +norm(coef( normalize_coefficients(p) )) + +abs_norm <- function(x) sum(abs(x)) +normalize_coefficients(p, norm = abs_norm) + +p <- mp(c("x", "2 y")) +normalize_coefficients(p) + + } diff --git a/man/deriv.mpoly.Rd b/man/deriv.mpoly.Rd index 41d32d3..99d1f49 100644 --- a/man/deriv.mpoly.Rd +++ b/man/deriv.mpoly.Rd @@ -4,7 +4,7 @@ \alias{deriv.mpoly} \title{Compute partial derivatives of a multivariate polynomial.} \usage{ -\method{deriv}{mpoly}(expr, var, ...) +\method{deriv}{mpoly}(expr, var, ..., bring_power_down = TRUE) } \arguments{ \item{expr}{an object of class mpoly} @@ -12,6 +12,8 @@ \item{var}{character - the partial derivative desired} \item{...}{any additional arguments} + +\item{bring_power_down}{if \code{FALSE}, x^n -> x^(n-1), not n x^(n-1)} } \value{ An object of class mpoly or mpolyList. @@ -21,12 +23,18 @@ This is a deriv method for mpoly objects. It does not call the \code{\link[stats:deriv]{stats::deriv()}}. } \examples{ -m <- mp("x y + y z + z^2") -deriv(m, "x") -deriv(m, "y") -deriv(m, "z") -deriv(m, c("x","y","z")) -deriv(m, "a") -is.mpoly(deriv(m, "x")) -is.mpolyList( deriv(m, c("x","y","z")) ) +p <- mp("x y + y z + z^2") +deriv(p, "x") +deriv(p, "y") +deriv(p, "z") +deriv(p, "t") +deriv(p, c("x","y","z")) + +is.mpoly(deriv(p, "x")) +is.mpolyList( deriv(p, c("x","y","z")) ) + +p <- mp("x^5") +deriv(p, "x") +deriv(p, "x", bring_power_down = FALSE) + } diff --git a/tests/testthat/test-components.R b/tests/testthat/test-components.R index 5cbcd6a..2cf1eb1 100644 --- a/tests/testthat/test-components.R +++ b/tests/testthat/test-components.R @@ -129,3 +129,51 @@ test_that("coef works", { + + +test_that("normalize_coefficients works", { + + p <- mp("(x + y)^2") + + expect_equal( + normalize_coefficients(p), + structure( + list( + c(x = 2, coef = 0.408248290463863), + c(x = 1, y = 1, coef = 0.816496580927726), + c(y = 2, coef = 0.408248290463863) + ), + class = "mpoly" + ) + ) + + abs_norm <- function(x) sum(abs(x)) + expect_equal( + normalize_coefficients(p, norm = abs_norm), + structure( + list( + c(x = 2, coef = 0.25), + c(x = 1, y = 1, coef = 0.5), + c(y = 2, coef = 0.25) + ), + class = "mpoly" + ) + ) + + expect_equal( + sum(coef(normalize_coefficients(p))^2), + 1 + ) + + expect_equal( + normalize_coefficients(mp(c("x", "5 y"))), + mp(c("x", "y")) + ) + + + + +}) + + + diff --git a/tests/testthat/test-deriv.R b/tests/testthat/test-deriv.R index ba7eee0..377a71e 100644 --- a/tests/testthat/test-deriv.R +++ b/tests/testthat/test-deriv.R @@ -47,6 +47,21 @@ test_that("vector indeterminates", { + + +test_that("bring_down_power works", { + + p <- mp("x^5") + + expect_equal( + mp("x^4"), + deriv(p, "x", bring_power_down = FALSE) + ) + +}) + + + test_that("gradient", { expect_equal(