Nothing
#' Define a multivariate polynomial.
#'
#' mp is a smart function which attempts to create a formal mpoly object from a
#' character string containing the usual representation of a multivariate
#' polynomial.
#'
#' @param string a character string containing a polynomial, see examples
#' @param varorder (optional) order of variables in string
#' @param stars_only if you format your multiplications using asterisks, setting
#' this to \code{TRUE} will reduce preprocessing time
#' @param vars a character vector of indeterminates
#' @return An object of class mpoly.
#' @author David Kahle \email{david@@kahle.io}
#' @seealso [mpoly()]
#' @name mp
#' @examples
#'
#' ( m <- mp("x + y + x y") )
#' is.mpoly( m )
#' unclass(m)
#'
#'
#' mp("x + 2 y + x^2 y + x y z")
#' mp("x + 2 y + x^2 y + x y z", varorder = c("y", "z", "x"))
#'
#' ( ms <- mp(c("x + y", "2 x")) )
#' is.mpolyList(ms)
#'
#'
#' gradient( mp("x + 2 y + x^2 y + x y z") )
#' gradient( mp("(x + y)^10") )
#'
#' # mp and the print methods are kinds of inverses of each other
#' ( polys <- mp(c("x + y", "x - y")) )
#' strings <- print(polys, silent = TRUE)
#' strings
#' mp(strings)
#'
#' @export
#' @rdname mp
make_indeterminate_list <- function (vars) {
make_indeterminate <- function(var, ...) {
v <- c(1, 1)
names(v) <- c(var, "coef")
structure(list(v), class = "mpoly")
}
uvars <- unique(vars)
l <- lapply(uvars, make_indeterminate)
names(l) <- uvars
l
}
# make_indeterminate_list("a")
# make_indeterminate_list(letters)
#' @export
#' @rdname mp
mp <- function (string, varorder, stars_only = FALSE) {
# deal with mpolyLists
if (length(string) > 1) {
# do basic mpoly parsing
ps <- structure(
lapply(string, mp, stars_only = stars_only),
class = "mpolyList"
)
# enforce varorder if present
if (!missing(varorder)) {
for (k in seq_along(ps)) {
ps[[k]] <- structure(
lapply(ps[[k]], function(term) {
vars_in_term <- intersect(varorder, names(term))
term[c(vars_in_term, "coef")]
}),
class = "mpoly"
)
}
}
# return early
return(ps)
}
# clean spaces if needed
if(!stars_only) {
# put *s in for spaces, twice for situations like "x y z"
while (str_detect(string, "([\\w\\^.*\\(\\)]+) +([\\w\\^.*\\(\\)]+)")) {
string <- str_replace_all(string, "([\\w\\^.*\\(\\)]+) +([\\w\\^.*\\(\\)]+)", "\\1*\\2")
}
# fix )('s and situations like 2(x+1)
# string <- str_replace_all(string, pattern = "\\)\\(", replacement = ")*(")
# string <- str_replace_all(string, "([\\w\\^.*\\(\\)]+)(\\(\\))", "\\1*\\2")
# fix things like "-x"
string <- str_replace_all(string, "^-([\\w\\^.*\\(]+)", "-1*\\1")
}
# parse using R's parser and mpoly arithmetic
expr <- parse(text = string)[[1]]
vars <- stringr::str_extract_all( deparse(expr), "(?<!\\d)[a-zA-Z]\\w*" )
vars <- unique(unlist(vars))
p <- eval(expr, envir = make_indeterminate_list(vars))
# if constant, make an mpoly
if (is.numeric(p)) return( structure(list(c(coef = p)), class = "mpoly") )
# reorder if needed and return
if (!missing(varorder)) {
p <- structure(
lapply(p, function(term) {
vars_in_term <- intersect(varorder, names(term))
term[c(vars_in_term, "coef")]
}),
class = "mpoly"
)
}
# return
p
}
#
#
#
# mp <- function(string, varorder){
#
# stopifnot(is.character(string))
#
# # if string is a vector of polys, return mpolyList
# if(length(string) > 1){
# if(missing(varorder)){
# mpolyList <- lapply(string, mp)
# } else {
# mpolyList <- lapply(string, mp, varorder = varorder)
# }
# class(mpolyList) <- "mpolyList"
# return(mpolyList)
# }
#
# # switch *'s for " "'s
# string <- str_replace_all(string, fixed("*"), " ")
#
# # fix leading -
# string <- str_replace(string, "^(\\s*-)", "0 + -1 ")
#
# # clean whitespace
# string <- str_replace_all(string, " {2,}", " ")
# string <- str_replace_all(string, "[\\n\\t]", " ")
#
# # clean -(x + y) -> -1 (x + y)
# string <- str_replace_all(string, "^ *- *\\(", "-1 (")
#
# # clean double parens
# string <- str_replace_all(string, fixed(")("), ") (")
#
# # check for bad things
# unmatched_parentheses_stop(string)
# empty_parenthetical_stop(string)
#
# # compute
# out <- parse_parenthetical_polynomial(string)
#
# # check varorder argument
# if(!missing(varorder)){
#
# vars <- vars(out)
#
# if(!all(vars %in% varorder)){
# error <- sprintf(
# "If specified, varorder must contain all computed vars - %s",
# str_c(vars, collapse = ", ")
# )
# stop(error, call. = FALSE)
# }
#
# # order vars appropriately
# vars <- intersect(varorder, vars)
# out <- reorder.mpoly(out, varorder = vars)
# }
#
# # return
# out
#
# }
#
#
#
# string <- "x ((x+y)+2)"
# parse_parenthetical_polynomial(string)
# parse_parenthetical_polynomial("x ((x+y) + 2)")
# parse_parenthetical_polynomial("-(x + y) + 2 x (x + y)^2 + 3 y")
# parse_parenthetical_polynomial <- function(string){
#
# # fix term joins
# terms <- extract_polynomial_terms(string)
#
# # parse into mpolys
# mpolys <- lapply(terms, parse_parenthetical_term)
#
# # add and return
# Reduce(`+.mpoly`, mpolys)
#
# }
# parse_parenthetical_term("3 y")
# parse_parenthetical_term(" 3 (x + y) 4 (x - y) ")
# parse_parenthetical_term("(x + y) (x - y)")
# parse_parenthetical_term("(x + y)")
# parse_parenthetical_term("(x + y)^2")
# parse_parenthetical_term("(x + y)(x-y)")
# parse_parenthetical_term("-2 (x + y)^2 (x - y)^0 4 (1+1)^3")
#
# # more complex usage
# parse_parenthetical_term("((x^2))")
# parse_parenthetical_term("((5^2))")
# string <- "(1+1) (2^3 z (x+y)^2)^2"
# parse_parenthetical_term(string)
# parse_parenthetical_term("6 (x)")
# parse_parenthetical_term("6.18033988749895 (x)")
# parse_parenthetical_term <- function(string){
#
# # short circuit if simpler
# if(!contains_parenthetical_expression(string))
# return(parse_nonparenthetical_term(string))
#
# # break into parenthetical pieces ("bubbles")
# pieces <- term_parentheticals(string)
# pieces <- pieces[pieces != ""]
#
# # mpoly pieces
# mpolys <- lapply(pieces, function(piece){
#
# # identify expression and exponent components
# expr <- str_extract(piece, "\\([-()\\w+ \\^.]+\\)")
# expr <- str_sub(expr, 2, -2) # take off parens
#
# # check for exponent on the outer parenthetical
# last_paren_ndx <- nchar(piece) - str_locate(str_rev(piece), fixed(")"))[[1]] + 1L
# string_after_paren <- str_sub(piece, last_paren_ndx + 1L) # "" or "^3"
#
# # if "^3", extract, otherwise 1
# if(str_detect(string_after_paren, fixed("^"))){
# exponent <- as.numeric(str_rev(str_extract(str_rev(string_after_paren), "[0-9]+"))) # gets first
# } else {
# exponent <- 1
# }
#
# # parse
# if(contains_nested_parenthetical_expression(piece)){
# parse_parenthetical_polynomial(expr)^exponent
# } else {
# parse_nonparenthetical_polynomial(expr)^exponent
# }
#
# })
#
# # product and return
# Reduce(`*.mpoly`, mpolys)
#
# }
# parse_nonparenthetical_polynomial(" -1")
# parse_nonparenthetical_polynomial("x-1")
# parse_nonparenthetical_polynomial("5-2x")
# parse_nonparenthetical_polynomial("5 - 2 x")
# parse_nonparenthetical_polynomial("5 + -2x")
# parse_nonparenthetical_polynomial("1--1")
# parse_nonparenthetical_polynomial("1 - - 1")
# parse_nonparenthetical_polynomial("5^2x")
# parse_nonparenthetical_polynomial("5^2-x")
# parse_nonparenthetical_polynomial("-x")
# parse_nonparenthetical_polynomial("-1")
# parse_nonparenthetical_polynomial("1+-x-x")
# parse_nonparenthetical_polynomial("1 - -3")
#
# parse_nonparenthetical_polynomial("-x + 2y - 4x - -4")
#
# string <- "-4 + 2+2 x + 1 x y^4 -3 prq^3 -y - 3 x 2 - 3 y -2"
# parse_nonparenthetical_polynomial(string)
# parse_nonparenthetical_polynomial("x + y")
# parse_nonparenthetical_polynomial("x - y+-xy")
# parse_nonparenthetical_polynomial("1e-2 x")
# parse_nonparenthetical_polynomial("1e+2 x")
# parse_nonparenthetical_polynomial <- function(string){
#
# # check to see if it's a single term
# if (!str_detect(string, "[+]") && !str_detect(str_sub(string, 2), "[-]")) {
# return(parse_nonparenthetical_term(string))
# }
#
# # regularize term joins (deal with minuses)
# string <- fix_term_joins(string)
#
# # split polynomial
# terms <- str_split(string, fixed(" + "))[[1]]
#
# # parse terms
# mpolyTerms <- lapply(terms, parse_nonparenthetical_term)
#
# # combine and return
# Reduce(`+.mpoly`, mpolyTerms)
#
# }
# parse_parenthetical_term("t1a")
# parse_nonparenthetical_term("12var 2 y 2x")
# parse_nonparenthetical_term("-2 7")
# parse_nonparenthetical_term("2 x y^2 3 2 3^2")
# parse_nonparenthetical_term("2 x -2") # -> warn
# parse_nonparenthetical_term("x")
# parse_nonparenthetical_term("-x") # error
# parse_nonparenthetical_term("+x") # correctly wrong
# parse_nonparenthetical_term("-5x")
# parse_nonparenthetical_term("-0x")
# parse_nonparenthetical_term("1.5x")
# parse_nonparenthetical_term("1.5^2x")
# parse_nonparenthetical_term("1e-2 x") # correctly error
# parse_nonparenthetical_term <- function(string){
#
# # fix spaces around exponents "x ^ 2" -> "x^2"
# string <- str_replace_all(string, " *\\^ *", "^")
#
# # fix spaces around minuses "x - 2" -> "x-2"
# string <- str_replace_all(string, " *- *", "-")
#
# # split based on spaces
# parts <- str_split(string, " ")[[1]]
# parts <- parts[nchar(parts) > 0] # for "2 -2"
#
# # if more than one negative provided error
# if(str_detect(str_sub(string, 2), fixed("-")))
# stop("Negative signs are only allowed at the beginning of terms.", call. = FALSE)
#
# # fix, e.g. "2x"
# smashed_var_bool <- str_detect(parts, "^[-. ^0-9]+[a-zA-Z]")
# if(any(smashed_var_bool)){
# places_to_break <- str_locate(parts[smashed_var_bool], "[a-zA-Z]")[,1]
# for(k in seq_along(places_to_break)){
# parts[smashed_var_bool][k] <- str_c(
# str_sub(parts[smashed_var_bool][k], 1, places_to_break[k]-1),
# "|",
# str_sub(parts[smashed_var_bool][k], places_to_break[k])
# )
# }
# parts <- unlist(str_split(parts, fixed("|")))
# }
#
# # fix, e.g. "-y"
# minus_var_bool <- str_detect(parts, "\\-[a-zA-Z]")
# if(any(minus_var_bool)){
# parts[minus_var_bool] <- str_c("-1 ", str_sub(parts[minus_var_bool], 2))
# parts <- unlist(str_split(parts, " "))
# }
#
# # collect numeric elements
# parts_with_vars <- str_detect(parts, "[a-zA-Z]")
# if(all(parts_with_vars)){
# coef <- 1L
# } else {
# coef <- prod(
# vapply(
# as.list(parts[which(!parts_with_vars)]),
# function(.) eval(parse(text = .)),
# double(1)
# )
# ) # this multiplies even, e.g., 5^2
# }
#
# # if only coefs are given, return
# if(all(parts_with_vars == FALSE)) return(mpoly(list(c(coef = coef))))
#
# # parse variable exponents
# var_parts <- parts[parts_with_vars]
# var_parts_with_exps_bool <- str_detect(var_parts, fixed("^"))
# var_parts[!var_parts_with_exps_bool] <- str_c(var_parts[!var_parts_with_exps_bool], "^1")
# var_parts <- str_split(var_parts, fixed("^"))
# vars <- vapply(var_parts, `[`, character(1), 1L)
# exps <- as.integer(vapply(var_parts, `[`, character(1), 2L))
# names(exps) <- vars
#
# # mpoly and return
# mpoly(list(c(coef = coef, exps)))
# }
# fix_term_joins("-2 - -2x + y - -3 y - 2")
# fix_term_joins("1e2x - 1e-2x + 1e+2x")
# fix_term_joins("1-1")
# fix_term_joins("x[1]")
# fix_term_joins("x[1,1]")
# fix_term_joins("1--1")
# fix_term_joins("1 - - 1")
# fix_term_joins("5 - 2 x")
# fix_term_joins("5^2x - 1")
# fix_term_joins("1+-xx-x")
# fix_term_joins("-1-1")
# fix_term_joins("1e-2 x")
# fix_term_joins("1e+2 x")
# fix_term_joins("1e2 x")
# fix_term_joins("-1-1-") # error
# fix_term_joins("-1-1+") # error
# fix_term_joins <- function(string){
#
# # make sure last char is not a sign
# if(str_detect(string, "[+-]$")) stop(sprintf("Term %s does not terminate.", string), call. = FALSE)
#
# # zero trick for leading symbol, e.g. "-1 + x" -> "0 + -1 + x"
# if (str_detect(string, "^[+-]")) {
# if (str_detect(string, "^[+-]{2,}")) stop(
# sprintf("%s cannot start an expression.", str_extract(string, "^[+-]+")),
# call. = FALSE
# )
# string <- str_c("0 + ", string)
# }
#
# # fix scientific notation
# sciRegex <- "[0-9.]+e[+-]?[0-9]+"
# while(str_detect(string, sciRegex)){
# stringToReplace <- str_extract(string, sciRegex)
# replacement <- format(as.numeric(stringToReplace))
# string <- str_replace(string, sciRegex, replacement)
# }
#
# # break string into pieces of terms and joins
# terms <- str_extract_all(string, "[\\w^.,|\\[\\]]+")[[1]]
# joins <- str_split(string, "[\\w^.,|\\[\\]]+")[[1]]
# if(joins[1] == "") joins <- joins[-1]
# if(joins[length(joins)] == "") joins <- joins[-length(joins)]
# if(length(joins) == 0L) return(string)
#
# # fix joins
# pureJoins <- str_replace_all(joins, "\\s", "")
# pureJoins[pureJoins == ""] <- "|"
# if(any(nchar(pureJoins) > 3)) stop("Arithmetic sign sequence of more than two detected.", call. = FALSE)
# cleanJoinMap <- c(
# "-" = " + -1 ", "+" = " + ", "--" = " + ",
# "++" = " + ", "+-" = " + -1 ", "-+" = " + -1 ", "|" = " "
# )
# cleanedJoins <- unname(cleanJoinMap[pureJoins]) # cbind(joins, cleanedJoins)
#
# # reconstruct
# n <- length(terms) + length(joins) # n always odd, first term always a \\w
# temp <- character(n)
# temp[seq.int(1L, n, 2L)] <- terms
# temp[seq.int(2L, n-1L, 2L)] <- cleanedJoins
# string <- str_c(temp, collapse = "")
#
# # strip leading "0 + " if needed
# if(str_sub(string, 1L, 4L) == "0 + ") string <- str_sub(string, 5L)
#
# # return
# string
# }
# string <- "-1 (x + y)+ 2 x (x + y) + 3 y"
# string <- "2 (1 + x + (x - y))+ 2 x (x + y) + 3 y"
# extract_polynomial_terms(string)
# extract_polynomial_terms <- function(string){
#
# # str_split(string, " *(?<!\\([\\w ]+)[+-] *")
#
# # run fix_term_joins on blanked strings to get protect parentheticals
# blanked_string <- blank_parentheticals(string, "|")
# piped_string <- fix_term_joins(blanked_string)
#
# # change +"s to *"s for breaking later
# # they distinguish polynomial terms
# piped_string <- str_replace_all(piped_string, fixed("+"), "*")
#
# # unprotect
# string_ndcs <- str_locate_all(blanked_string, "[|]+")[[1]]
# piped_ndcs <- str_locate_all(piped_string, "[|]+")[[1]]
# if(nrow(string_ndcs) > 0){
# for(k in 1:nrow(string_ndcs)){
# str_sub(piped_string, piped_ndcs[k,1], piped_ndcs[k,2]) <-
# str_sub(string, string_ndcs[k,1], string_ndcs[k,2])
# }
# }
#
# # split
# str_split(piped_string, fixed("*"))[[1]]
# }
# an inner parenthetical is one that does not contain parentheticals
# extract_leftmost_inner_parenthetical("(x + 5)")
# extract_leftmost_inner_parenthetical("(x + 5)", contents_only = TRUE)
#
# extract_leftmost_inner_parenthetical("(x + 5)^10")
# extract_leftmost_inner_parenthetical("(x + 5)^10", contents_only = TRUE)
# extract_leftmost_inner_parenthetical("((x + 5)^10+2)^2")
# extract_leftmost_inner_parenthetical("((x + 5)^10+2)", contents_only = TRUE)
# extract_leftmost_inner_parenthetical("(1 + (x + 5)^10+2)^2")
# extract_leftmost_inner_parenthetical <- function(string, contents_only = FALSE){
# string <- str_extract(string, "\\([^()]*\\)(?:\\^[0-9]+)?")
# if(!contents_only) return(string)
# str_extract(string, "\\(.*\\)") ->.; str_sub(., 2L, -2L)
# }
# blank_parentheticals(" -1 1 x (3 x + -1 (7 + -1 2 x))^2 7 (x + 1) -3 ")
# blank_parentheticals(" -1 1 x (3 x + -1 (7 + -1 2 x))^2 7 (x + 1) -3 ", "*")
# blank_parentheticals(" -1 1 x (3 x + -1 (7 + -1 2 x))^2 7 (x + 1) -3 ", "_")
# blank_parentheticals <- function(string, char = "-"){
# # " -1 1 x (3 x + -1 (7 + -1 2 x))^2 7 (x + 1) -3 " ->
# # " -1 1 x ------------------------- 7 ------- -3 "
# # this blanks parentheticals from the inside out
# # inside parentheticals are done first
#
# while(contains_parenthetical_expression(string)){
# bad <- extract_leftmost_inner_parenthetical(string)
# string <- str_replace(
# string,
# "\\([^()]*\\)(?:\\^[0-9]+)?",
# str_dup(char, nchar(bad))
# )
# }
# string
# }
# string <- " -3 -1 (x + y)^2 4 (x - y)x 4 "
# extract_nonparenthetical_elements(string)
# string <- " (x + y)^2 (x - y)(x) "
# extract_nonparenthetical_elements(string)
# extract_nonparenthetical_elements <- function(string){
#
# # remove parenthetical stuff
# parenthetical_regex <- "\\([-+*a-zA-Z0-9.^ ()]+\\)(\\^\\d+)?"
# nonparem_elts <- str_remove_all(string, parenthetical_regex)
# nonparem_elts <- str_replace_all(nonparem_elts, "\\s+", " ")
# nonparem_elts <- str_trim(nonparem_elts)
#
# # parenthesize and return
# if (nonparem_elts == "") {
# ""
# } else {
# str_c("(", str_trim(nonparem_elts), ")")
# }
# }
# string <- " -3 (x + y)^2 4 (x - y)x 4 "
# delete_nonparenthetical_elements(string)
# string <- " (x + y)^2 (x - y) (x) (y) "
# delete_nonparenthetical_elements(string)
# string <- ".2 (x)"
# delete_nonparenthetical_elements(string)
# extract_parenthetical_elements <- function(string){
#
# parenthetical_regex <- "\\([-+*a-zA-Z0-9.^ ()]+\\)(\\^\\d+)?"
# str_extract_all(string, parenthetical_regex)[[1]]
#
# }
# string <- " -3 (x + y)^2 4 (x - y)(x)x 4 "
# term_parentheticals(string)
# string <- " -(x + y)^2 3(x - y)(x) "
# term_parentheticals(string)
# string <- ".2 (x)"
# term_parentheticals(string)
# term_parentheticals <- function(string){
#
# nonparens <- extract_nonparenthetical_elements(string)
# parens <- extract_parenthetical_elements(string)
# c(nonparens, parens)
#
# }
# contains_parenthetical_expression <- function(string){
# any(str_detect(string, fixed("(")))
# }
# contains_nested_parenthetical_expression("5+5")
# contains_nested_parenthetical_expression("(5+5)")
# contains_nested_parenthetical_expression("((5+5))")
# contains_nested_parenthetical_expression("x + (5 y) + 2")
# contains_nested_parenthetical_expression("x + ((5 y) + 2)")
# contains_nested_parenthetical_expression <- function(string){
# only_parentheses <- str_replace_all(string, "[^()]", "")
# str_detect(only_parentheses, fixed("(("))
# }
# unmatched_parentheses_stop <- function(string){
# if(contains_parenthetical_expression(string)){
# open_paren_count <- str_count(string, fixed("("))
# closed_paren_count <- str_count(string, fixed(")"))
# if (open_paren_count > closed_paren_count){
# stop("Parenthetical error: excess ('s detected.", call. = FALSE)
# } else if(open_paren_count < closed_paren_count) {
# stop("Parenthetical error: excess )'s detected.", call. = FALSE)
# }
# }
# invisible()
# }
# empty_parenthetical_stop <- function(string) {
# if (str_detect(string, "\\( *\\)")) {
# stop("Expression contains empty parenthetical.", call. = FALSE)
# }
# }
# str_rev <- function(string) str_c(rev.default(str_split(string, "")[[1]]), collapse = "")
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.