# # yacas is in YACAS_HOME. If unset then on Windows the yacas # distributed with R is used and otherwise the yacas on the # path is used. If YACAS_HOME is a directory, filename # is assumed to be yacas.exe on Windows and yacas otherwise. # # scripts are in YACAS_SCRIPTS or in yacas home directory # if not specified. If YACAS_SCRIPTS is a directory, filename # is assumed to be scripts.dat . # # init file is in YACAS_INIT or in yacdir within the Ryacas # package if not specified. If YACAS_INIT is a directory, filename # is assumed to be R.ys. yacasInvokeString <- function(method = c("socket", "system"), yacas.init , yacas.args = "-pc --single-user-server") { yacas.invoke.string <- Sys.getenv("YACAS_INVOKE_STRING") if (Sys.getenv("YACAS_INVOKE_STRING") != "") return(yacas.invoke.string) method <- match.arg(method) whole.path <- function(path, defpath, deffile) { if (path == "") path <- defpath if (file.info(path)$isdir) file.path(path, deffile) else path } if (.Platform$OS.type == "windows") { # yacas.args <- "-pc" yacas <- yacasFile("yacas.exe") if (missing(yacas.init)) yacas.init <- yacasFile("R.ys", "/") yacas.post <- "" yacas.scripts <- yacasFile("scripts.dat", "/") yacas.scripts <- paste("--archive", shQuote(yacas.scripts)) } else { # yacas.args <- "-pc" yacas <- "yacas" if (missing(yacas.init)) yacas.init <- file.path(system.file(package = "Ryacas"), "yacdir/R.ys") yacas.post <- " " yacas.scripts <- "" } server.string <- if(method == "socket") "--server 9734" else "" if (yacas.init != "") yacas.init <- paste("--init", shQuote(yacas.init)) paste(yacas, yacas.init, yacas.scripts, yacas.args, server.string, yacas.post) } runYacas <- function(method = "system", yacas.args = "", yacas.init = "") { cmd <- yacasInvokeString(method = method, yacas.args = yacas.args, yacas.init = yacas.init) if (.Platform$OS.type == "windows") system(cmd, wait = FALSE, invisible = FALSE) else system(cmd, wait = FALSE) } haveYacas <- function() !inherits(try(yacas("1", method = "system"), silent = TRUE), "try-error") yacasStart <- function(verbose = FALSE, method = c("socket", "system")) { method <- match.arg(method) if (method == "system") return() if (!capabilities("sockets")) stop("no socket capabilties") yacasStop(verbose = FALSE) cmd.str <- yacasInvokeString(method = method) print("Starting Yacas!") # return path using defpath and deffile as fill-in defaults if (verbose) cat("Invoking Yacas with command line:\n ", cmd.str, "\n") system(cmd.str, wait = FALSE) # if (.Platform$OS.type == "windows") { # system(cmd.str, wait = FALSE) #} else { # system(paste(cmd.str, "&")) #} Sys.sleep(1) assign(".yacCon", socketConnection(host = "127.0.0.1", port=9734, server = FALSE, blocking = FALSE, open = "a+", encoding = getOption("encoding")), .GlobalEnv) invisible(0) } isConnection <- function(x) { opened <- summary(x)$opened identical(opened, "opened") || identical(opened, "closed") } yacasStop <- function(verbose = TRUE) { if (exists(".yacCon", .GlobalEnv)) { # if (isConnection(get(".yacCon", .GlobalEnv))) try(close(.yacCon)) .yacCon <- get(".yacCon", .GlobalEnv) if (isConnection(.yacCon)) { writeLines("Exit();", .yacCon) try(close(.yacCon)) } rm(.yacCon, envir = .GlobalEnv) } # if (.Platform$OS.type == "windows") system("taskkill /im yacas.exe") if (verbose) cat("Thank you for using yacas\n") return(invisible(0)) } .Last.lib <- function(lib) { if (exists(".yacCon", .GlobalEnv)) yacasStop() # next statement has no effect except on Windows XP Pro } # proper counting of lines read in, and proper handling of them. yacas <- function(x, ...) UseMethod("yacas") yacas.character <- function(x, verbose = FALSE, method, retclass = c("expression", "character", "unquote"), addSemi = TRUE, ...) { addSemiFn <- function(x) { x <- sub(";[[:blank:]]*$", "", x) x <- paste(x, ";", collapse='', sep='') return(x) } retclass <- match.arg(retclass) if (missing(method)) method <- getOption("yacas.method") method <- match.arg(method, c("socket", "system")) if (retclass == "expression") { x <- paste("Eval(",x,");") } else { if (addSemi) x <- addSemiFn(x) } if (method == "system") { # chunk1 <- if (.Platform$OS.type == "windows") # system(yacasInvokeString(method = "system"), # input = x, intern = TRUE, invisible = TRUE) # else { # f.tmp = file.path(tempdir(), ".R/yacas.tmp") # if (!file.create(f.tmp)) { # warning("cannot create tmp yacas input file") # return(FALSE) # } # out <- file(f.tmp, open = "a") ## cat(paste("Echo('Executing :'", x, ");")) # cat(x, file=out) # close(out) # system(paste(yacasInvokeString(method = "system"), f.tmp)) # } chunk1 <- system(yacasInvokeString(method = "system"), input = x, intern = TRUE) chunk1 <- sub("^(In> *| +)", "", chunk1) chunk1 <- head(tail(chunk1, -6), -3) yac.res <- chunk1 chunk2 <- "" } else { # if connection does not exist or its not a connection # or its closed, startup Yacas. if (!exists(".yacCon", .GlobalEnv) || !isConnection(get(".yacCon", .GlobalEnv)) || summary(get(".yacCon", .GlobalEnv))$opened == "closed") yacasStart(verbose = isTRUE(verbose)) yac.res <- c() # print(x) if (!is.na(pmatch(verbose, c(TRUE, "input")))) cat("Sending to yacas:", x, "", sep = "\n") .yacCon <- get(".yacCon", .GlobalEnv) writeLines(x, .yacCon) delim <- "]" yac.res <- c() while (sum(delim == yac.res) < 2) { yac.out <- readLines(.yacCon) yac.res <- c(yac.res, yac.out) } yac.res <- yac.res[yac.res != ""] flush(.yacCon) # print all non-delims in verbose mode is.delim <- yac.res == delim # print non-delims if (any(!is.delim) && !is.na(pmatch(verbose, c(TRUE, "output")))) print(yac.res[!is.delim]) w <- which(is.delim)[1:2] chunk1 <- yac.res[seq(1, length = w[1]-1)] chunk2 <- yac.res[seq(w[1]+1, length = diff(w)-1)] } if (yac.res[1] == "") { text <- OpenMath2R(chunk1) if (retclass == "expression") text <- parse(text = text, srcfile = NULL) # text <- format(text)[[1]] if (retclass == "unquote") text <- sub("^['\"](.*)['\"]", "\\1", text) result <- list(text = text, OMForm = chunk1) } else { if (length(chunk1) > 0) { # PrettyForm # k is index of in chunk1 k <- grep("", chunk1) # only keep first k-1 elements of chunk1 if (length(k) > 0) chunk1 <- chunk1[seq(length = k-1)] result <- list(NULL, PrettyForm = chunk1) } else result <- list(NULL, YacasForm = chunk2) } class(result) <- "yacas" result } # test # yacas("Pi+Sin(x)", retclass = "character", OM=TRUE) as.language <- function(x) parse(text=paste(deparse(x)))[[1]] bodyAsExpression <- function(x) as.expression(as.language(body(x))) yacas.expression <- function(x, ...) { x <- deparse(yparse(x), width.cutoff = 200) x <- gsub("\"","", x) .Class <- "character" NextMethod(x, ...) } yparse <- function(x) { if (!is.expression(x)) return options(show.error.messages = FALSE) # ynext does all translations, yrewrite special rewriting x[[1]] <- yrewrite(ynext(x[[1]])) options(show.error.messages = TRUE) x[[1]] } ynext <- function(x) { if (length(x) == 1) { x <- ysub(x) # print(paste("1:", x)) } else for (i in 1:length(x)) { if (length(x[[i]]) >= 1) { # print(paste("x[[", i, "]]->", x[[i]])) # x[[i]] <- ynext(x[[i]]) # Added yrewrite to make ynext really recursive x[[i]] <- yrewrite(ynext(x[[i]])) # print(paste("x[[", i, "]]->", x[[i]])) # print(paste(length(x), ":", x)) } } x } ysub <- function(x) { if (!match(as.character(x), c("-", "+", "/", "^", "*"), nomatch = 0)) { if (!typeof(x) == "double") { if (match(toString(x), transtab[,"R"], nomatch = 0) >0 ) { x <- trans(toString(x), from="R", to="yacas") if (x == '":="') x <- ":=" # mode(x) <- "name" x <- as.name(x) } else if (typeof(x) == "symbol") { try(x <- ynext(eval(x)[[1]])) } } } x } yrewrite <- function(x) { if (length(x) > 1) { if (x[[1]] == quote(Integrate)) { x <- yIntegrate(x) } if (x[[1]] == quote(Deriv)) { x <- yDeriv(x) } if (x[[1]] == quote(Limit)) { x <- yLimit(x) } if (x[[1]] == quote(factorial)) { x <- yFactorial(x) } if (x[[1]] == quote(sequence)) { x <- ySequence(x) } if (x[[1]] == as.name(":=") && length(x) == 3 && length(x[[3]]) > 2 && x[[3]][[1]] == as.name("function")) { x <- yAssignFunction(x) } } x } # Used to separatedly parse argument expressions yUnlist <- function(x) { out <- c() if (length(x) > 1) { out <- paste(out, "UnList({", toString(x), "})", sep="") } else out <- paste(out, x, sep="") } yFactorial <- function(x) { # print(paste("factorial:", x)) paste("Eval(",yUnlist(x[[2]]), ")!", sep="") } ySequence <- function(x) { # print(paste("sequence:", x)) paste("Eval(",yUnlist(x[[2]]) ," .. ",yUnlist(x[[3]]) ,")", sep="") } yLimit <- function(x) { out <- c(); res <- "" res <- try(mode(eval(x[[3]]))) if (res=="numeric") x[[3]] <- eval(x[[3]]) out <- paste("Apply(", x[[1]], ", {", yUnlist(x[[2]]), ", Eval(", yUnlist(x[[3]]), ")", sep="") x <- paste(out, ", ", yUnlist(x[[4]]), "})", sep="") } yDeriv <- function(x) { # tmp <- yparse(x[2][1]) out <- c() # if just function name specified then add third arg if (length(x) == 2) x[[3]] <- "x" if (is.name(x[[3]])) { x[[3]] <- as.character(x[[3]]) } else { # translate c to List if (identical(x[[3]][[1]], as.name("c"))) x[[3]][[1]] <- as.name("List") # translate Deriv to D for higher order deriv if (identical(x[[3]][[1]], as.name("List"))) x[[1]] <- "D" # remove quotes on variables x[[3]] <- gsub('"', '', format(x[[3]])) } out <- paste("Apply(", x[[1]], ", {", format(x[[3]]), sep="") # if only function name specified append (x) to make F(x) x <- if (is.name(x[[2]])) paste(out, ", ", x[[2]], "(", x[[3]], ")})", sep="") else paste(out, ", ", format(x[[2]]), "})", sep="") } yIntegrate <- function(x) { out <- c() if (is.name(x[[2]])) x[[2]] <- paste(x[[2]], "(x)") is.x.specified <- length(x) == 3 || length(x) == 5 out <- if (is.x.specified) paste("Apply(", x[[1]], ", {", sep="") else paste("Apply(", x[[1]], ", {x, ", sep="") for (i in seq(3, length = length(x) - 2)) { if (length(x[[i]]) > 1) { out <- paste(out, yUnlist(x[[i]]), sep="") } else out <- paste(out, x[[i]], sep="") out <- paste(out, ", ", sep="") } out <- paste(out, format(x[[2]]), "})", sep="") out } yAssignFunction <- function(x) { paste(x[[2]], "(", paste(names(x[[3]][[2]]), collapse = ","), ")", x[[1]], format(body(eval(x[[3]]))), sep = "" ) } yacas.function <- function(x, ...) { funname <- deparse(substitute(x)) a <- paste( "(", paste(names(formals(x)), collapse = ","), ")" ) b <- format(body(x)) e <- as.expression(parse(text = b)) s <- yparse(e) x <- paste(funname, a, ":=", format(s), sep = "") .Class <- "character" NextMethod(x) } yacas.formula <- function(x, ...) { x <- as.expression(as.language(x[[length(x)]])) .Class <- "expression" NextMethod(x) } yacas.yacas <- function(x, ...) { x <- x[[1]] stopifnot(is.expression(x)) .Class <- "expression" NextMethod(x) } as.Expr.formula <- function(x) as.expression(as.language(x[[length(x)]])) Eval <- function(x, env = parent.frame(), ...) UseMethod("Eval") Eval.yacas <- function(x, env = parent.frame(), ...) eval(x[[1]], env = env) as.expression.yacas <- function(x, ...) x[[1]] as.character.yacas <- function(x, ...) as.character(x[[1]])