library(Ryacas)
The low-level interface consists of these two main functions:
yac_str(x)
: Evaluate yacas
command
x
(a string) and get result as
string/character.yac_expr(x)
: Evaluate yacas
command
x
(a string) and get result as an R
expression.Note, that the yacas
command x
is a string
and must often be built op using
paste()
/paste0()
. Examples of this will be
shown in multiple examples below.
A short summary of often-used yacas
commands are found
in the section “yacas
reference” in the “Getting started”
vignette. A short summary of Ryacas
’s low-level functions
are also found in the section “Ryacas
low-level reference”
at the end of this document.
Note that the yacas documentation is a very useful resource.
First, consider this polynomial:
<- "x^2 + 4 + 2*x + 2*x" eq
Now, perform yacas
operations, and get result as
string/character:
yac_str(eq) # No task was given to yacas, so we simply get the same returned
## [1] "x^2+2*x+2*x+4"
yac_str(paste0("Simplify(", eq, ")"))
## [1] "x^2+4*x+4"
yac_str(paste0("Factor(", eq, ")"))
## [1] "(x+2)^2"
yac_str(paste0("TeXForm(Factor(", eq, "))"))
## [1] "\\left( x + 2\\right) ^{2}"
\[ \left( x + 2\right) ^{2} \]
Also see yacas documentation on Simplify(), Factor() and TeXForm().
Instead of the pattern paste0("Simplify(", eq, ")")
etc., there exists a helper function y_fn()
that does
this:
y_fn(eq, "Simplify")
## [1] "Simplify(x^2 + 4 + 2*x + 2*x)"
yac_str(y_fn(eq, "Simplify"))
## [1] "x^2+4*x+4"
yac_str(y_fn(eq, "Factor"))
## [1] "(x+2)^2"
yac_str(y_fn(y_fn(eq, "Factor"), "TeXForm"))
## [1] "\\left( x + 2\\right) ^{2}"
As you see, there are a lot of nested function calls. That can be
avoided by using magrittr
’s pipe %>%
(automatically available with Ryacas
) together with the
helper function y_fn()
:
%>% y_fn("Simplify") eq
## [1] "Simplify(x^2 + 4 + 2*x + 2*x)"
%>% y_fn("Simplify") %>% yac_str() eq
## [1] "x^2+4*x+4"
%>% y_fn("Factor") %>% yac_str() eq
## [1] "(x+2)^2"
%>% y_fn("Factor") %>% y_fn("TeXForm") %>% yac_str() eq
## [1] "\\left( x + 2\\right) ^{2}"
Below, we will stick to the standard way of calling the functions, and not using the pipe, but now it has been demonstrated if the user prefers that way.
We will not use the pipe operator below, but just demonstrate its usage.
Now, again perform yacas
operations, but get result as
an R
expression, e.g. for continued computations:
eq
## [1] "x^2 + 4 + 2*x + 2*x"
%>% yac_expr() # Alternative to "yac_expr(eq)" eq
## expression(x^2 + 2 * x + 2 * x + 4)
<- eq %>% y_fn("Factor")
cmd cmd
## [1] "Factor(x^2 + 4 + 2*x + 2*x)"
<- yac_expr(cmd)
e e
## expression((x + 2)^2)
eval(e, list(x = 2))
## [1] 16
To work with matrices and vectors, you need to realise that
yacas
and R
has different ways of representing
these objects. yacas
represents vectors as a list, and a
matrix as a list of lists (each list is a row).
You can work with these directly. Here illutrated with vectors:
<- "2*{x, x^2, x^3}"
cmd %>% yac_str() cmd
## [1] "{2*x,2*x^2,2*x^3}"
<- cmd %>% yac_expr()
e e
## expression(c(2 * x, 2 * x^2, 2 * x^3))
eval(e, list(x = 1.5))
## [1] 3.00 4.50 6.75
And then illutrated with matrices. First with purely numeric contents:
<- "{{1, 2}, {3, 4}}"
cmd yac_str(cmd)
## [1] "{{1,2},{3,4}}"
y_print(cmd) # Convenience function for prettier print
## {{1, 2},
## {3, 4}}
<- cmd %>% yac_expr()
e e
## expression(rbind(c(1, 2), c(3, 4)))
eval(e)
## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
Also in \(\LaTeX\) (yacas documentation on TeXForm()):
%>% y_fn("TeXForm") %>% yac_str() cmd
## [1] "\\left( \\begin{array}{cc} 1 & 2 \\\\ 3 & 4 \\end{array} \\right) "
But it also works with symbolic contents:
<- paste0("a * ", cmd, "")
cmd1 <- cmd1 %>% y_fn("Inverse")
cmd2 cmd2
## [1] "Inverse(a * {{1, 2}, {3, 4}})"
%>% yac_str() cmd2
## [1] "{{1/a+(6*a^2)/(a^2*(4*a-(6*a^2)/a)),(-(2*a)/a)/(4*a-(6*a^2)/a)},{(-(3*a)/a)/(4*a-(6*a^2)/a),1/(4*a-(6*a^2)/a)}}"
%>% y_fn("TeXForm") %>% yac_str() cmd2
## [1] "\\left( \\begin{array}{cc} \\frac{1}{a} + \\frac{6 a ^{2}}{a ^{2} \\left( 4 a - \\frac{6 a ^{2}}{a} \\right) } & \\frac{ - \\frac{2 a}{a} }{4 a - \\frac{6 a ^{2}}{a} } \\\\ \\frac{ - \\frac{3 a}{a} }{4 a - \\frac{6 a ^{2}}{a} } & \\frac{1}{4 a - \\frac{6 a ^{2}}{a} } \\end{array} \\right) "
\[ \left( \begin{array}{cc} \frac{1}{a} + \frac{6 a ^{2}}{a ^{2} \left( 4 a - \frac{6 a ^{2}}{a} \right) } & \frac{ - \frac{2 a}{a} }{4 a - \frac{6 a ^{2}}{a} } \\ \frac{ - \frac{3 a}{a} }{4 a - \frac{6 a ^{2}}{a} } & \frac{1}{4 a - \frac{6 a ^{2}}{a} } \end{array} \right) \]
paste0(cmd2, "*", cmd1) %>%
y_fn("Simplify") %>%
yac_str()
## [1] "{{1,0},{0,1}}"
<- cmd2 %>% yac_expr()
e2 eval(e2, list(a = 2.2))
## [,1] [,2]
## [1,] -0.9090909 0.4545455
## [2,] 0.6818182 -0.2272727
R
’s character matricesThe above is fine when writing yacas
vectors and
matrices by hand. But often one would want to exploit R
’s
convenient functions to work with matrices.
The central idea to make this possible is to work with R
character matrices. We provide two helper functions to go back and forth
between R
and yacas
:
as_y(x)
: Convert R
character matrix
x
to a yacas
representationas_r(x)
: Convert a yacas
representation
x
to a R
character matrixBelow, we illustrate the usage of both functions.
First, we create a character matrix using R
:
<- matrix(0, nrow = 3, ncol = 3)
Achr diag(Achr) <- 1
2, 3] <- "a"
Achr[1, 3] <- "a"
Achr[ Achr
## [,1] [,2] [,3]
## [1,] "1" "0" "a"
## [2,] "0" "1" "a"
## [3,] "0" "0" "1"
Note how this is a character matrix. If we want to find it’s inverse
symbolically using yacas
, it must first be represented as a
yacas
matrix:
<- Achr %>% as_y()
Ayac Ayac
## [1] "{{1, 0, a}, {0, 1, a}, {0, 0, 1}}"
Now, we can find the inverse:
<- Ayac %>% y_fn("Inverse")
cmd %>% yac_str() cmd
## [1] "{{1,0,-a},{0,1,-a},{0,0,1}}"
A nicer representation can be obtained in (at least) four ways:
<- cmd %>% yac_str()
way1 %>% y_print() way1
## {{ 1, 0, -a},
## { 0, 1, -a},
## { 0, 0, 1}}
<- cmd %>% y_fn("TeXForm") %>% yac_str()
way2 way2
## [1] "\\left( \\begin{array}{ccc} 1 & 0 & - a \\\\ 0 & 1 & - a \\\\ 0 & 0 & 1 \\end{array} \\right) "
<- cmd %>% y_fn("PrettyForm") %>% yac_str()
way3 %>% cat() # Result of PrettyForm() must be printed way3
##
## / \
## | ( 1 ) ( 0 ) ( -( a ) ) |
## | |
## | ( 0 ) ( 1 ) ( -( a ) ) |
## | |
## | ( 0 ) ( 0 ) ( 1 ) |
## \ /
<- cmd %>% yac_str()
way4 way4
## [1] "{{1,0,-a},{0,1,-a},{0,0,1}}"
%>% as_r() way4
## [,1] [,2] [,3]
## [1,] "1" "0" "-a"
## [2,] "0" "1" "-a"
## [3,] "0" "0" "1"
%>% as_r() %>% print(quote = FALSE) way4
## [,1] [,2] [,3]
## [1,] 1 0 -a
## [2,] 0 1 -a
## [3,] 0 0 1
Say we want to subset it to only consider a submatrix. To do that, we
can use R
’s facilities:
<- way4 %>% as_r()
A_inv_yac <- A_inv_yac[2:3, 2:3]
Bchr Bchr
## [,1] [,2]
## [1,] "1" "-a"
## [2,] "0" "1"
%>% as_y() Bchr
## [1] "{{1, -a}, {0, 1}}"
%>% as_y() %>%
Bchr y_fn("Inverse") %>%
yac_str() %>%
as_r()
## [,1] [,2]
## [1,] "1" "a"
## [2,] "0" "1"
yacas
variablesyacas
also has variables. They are assigned by
:=
.
Consider this example:
yac_str("poly := (x-3)*(x+2)")
## [1] "(x-3)*(x+2)"
If the output is not necessary, it can be suppressed by using
yac_silent()
instead of yac_str()
:
yac_silent("poly := (x-3)*(x+2)")
We can now list yacas
variables (I
is the
imaginary unit):
yac_str("Variables()")
## [1] "{t,rformBitwiseOps,TeXForm'FuncPrec,I,j,poly,Arow,nd}"
yac_str("Expand(poly)")
## [1] "x^2-x-6"
"poly" %>% y_fn("Expand") %>% yac_str()
## [1] "x^2-x-6"
Yacas can sum an expression. The syntax is
Sum(var, from, to, body)
as described in the yacas
documentation of Sum()
. For example we can sum \(a^k\) for \(k =
0\) to \(k = n\) as follows:
yac_str("Sum(k, 0, n, a^k)")
## [1] "(1-a^(n+1))/(1-a)"
Yacas can also take the limit of an expression. The syntax is
Limit(var, val) expr
as described in the yacas
documentation of Limit()
. For example we can take the
limit of \((1+(1/n))^n\) for \(n \to \infty\) as follows:
<- "Limit(n, Infinity) (1+(1/n))^n"
cmd yac_str(cmd)
## [1] "Exp(1)"
yac_expr(cmd)
## expression(exp(1))
This can also be used to illustrate taking derivatives, e.g. the derivative of sine:
yac_str("Limit(h, 0) (Sin(x+h)-Sin(x))/h")
## [1] "Cos(x)"
Say we want to find roots of poly
. First note that the
equality in yacas
is ==
. Then:
<- "Solve(poly == 0, x)"
cmd %>% yac_str() cmd
## [1] "{x==(-2),x==3}"
Note that the default in yacas’s Solve()
is to find
roots if no equality sign is provided:
<- "Solve(poly, x)"
cmd %>% yac_str() cmd
## [1] "{x==(-2),x==3}"
If we want the solution without the variable name x
and
the equality symbol ==
, we can use Ryacas
helper function y_rmvars()
:
cmd
## [1] "Solve(poly, x)"
%>% y_rmvars() %>% yac_str() cmd
## [1] "{-2,3}"
%>% y_rmvars() %>% yac_expr() cmd
## expression(c(-2, 3))
We can also use y_fn()
:
"poly == 0" %>% y_fn("Solve", "x")
## [1] "Solve(poly == 0, x)"
"poly" %>% y_fn("Solve", "x") # default is == 0
## [1] "Solve(poly, x)"
"poly == 0" %>% y_fn("Solve", "x") %>% y_rmvars() %>% yac_str()
## [1] "{-2,3}"
Say we have a function:
<- function(x, y) 2*x^2 + 3*y + y*x^2
f <- body(f)
f_body f_body
## 2 * x^2 + 3 * y + y * x^2
<- as.character(as.expression(body(f)))
f_body_chr f_body_chr
## [1] "2 * x^2 + 3 * y + y * x^2"
# or:
# f_body_chr <- "2 * x^2 + 3 * y + y * x^2"
# f <- function(x, y) NULL
# body(f) <- parse(text = f_body_chr, keep.source = FALSE)
The gradient can be found using yacas
(D(x) expr
is the derivative of expr
with
respect to x
):
<- paste0("{ D(x) ", f_body_chr, ", D(y) ", f_body_chr, " }")
cmd_g cmd_g
## [1] "{ D(x) 2 * x^2 + 3 * y + y * x^2, D(y) 2 * x^2 + 3 * y + y * x^2 }"
<- yac_expr(cmd_g)
g_body g_body
## expression(c(4 * x + y * 2 * x, x^2 + 3))
<- function(x, y) NULL
g body(g) <- g_body
g
## function (x, y)
## c(4 * x + y * 2 * x, x^2 + 3)
g(2, 4)
## [1] 24 7
The Hessian matrix can also be found using yacas
:
<- paste0("HessianMatrix(", f_body_chr, ", {x, y})")
cmd_H cmd_H
## [1] "HessianMatrix(2 * x^2 + 3 * y + y * x^2, {x, y})"
<- yac_expr(cmd_H)
H_body H_body
## expression(rbind(c(2 * y + 4, 2 * x), c(2 * x, 0)))
<- function(x, y) NULL
H body(H) <- H_body
H
## function (x, y)
## rbind(c(2 * y + 4, 2 * x), c(2 * x, 0))
H(2, 4)
## [,1] [,2]
## [1,] 12 4
## [2,] 4 0
Ryacas
low-level referencePrinciple:
yac_*(x)
functions evaluate/run yacas
command x
; the result varies depending on which of the
functions usedy_*(x)
various utility functions (not involving calls
to yacas
)Reference:
yacas
expressions
yac(x, rettype = c("str", "expr", "silent"))
: Evaluate
yacas
command x
(a string) and get result
determined by rettype
(default "str"
).yac_expr(x)
: Evaluate yacas
command
x
(a string) and get result as an R
expression.yac_silent(x)
: Evaluate yacas
command
x
(a string) silently; useful for creating
yacas
variables. string/character.yac_str(x)
: Same as yac_expr()
, but get
result as string/character.as_y(x)
: Convert R
character matrix
x
to a yacas
representationas_r(x)
: Convert a yacas
representation
x
to an R
objecty_fn(x, fn, ...)
: Helper function to prepare a call for
yacas
, e.g. y_fn("x^2 - 1", "Factor")
is gives
"Factor(x^2 - 1)"
; ...
are additional
arguments: y_fn(x, fn, ...)
gives
fn(x, ...)
y_rmvars(x)
: Removes variables such that
{x == 2}
instead gets {2}
; remember to call
yacas
with e.g. yac_str()
or
yac_expr()
y_print(x)
: Pretty print yacas strings, e.g. a yacas
matrixyac_core(x)
: Evaluate yacas
command
x
(a string) and get both result and side effects; used in
the implementation of yac_expr()
,
yac_silent()
, and yac_str()