---
title: "Elaborate reference of `Ryacas` functionality"
author: "Rob Goedman, Gabor Grothendieck, Søren Højsgaard, Ayal Pinkus and Mikkel Meyer Andersen"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Elaborate reference of Ryacas functionality}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

```{r, message=FALSE}
library(Ryacas)
```


# Introduction

`Ryacas` makes the `yacas` computer algebra system available from
within `R`. The name `yacas` is short for "Yet Another Computer Algebra
System". The `yacas` program 
is developed by Ayal Pinkhuis (who is also the maintainer)
and others, and is available at <http://www.yacas.org/> for various
platforms. There is a comprehensive documentation (300+ pages) of
`yacas` (also available at
<http://www.yacas.org/>) and the
documentation contains many examples.

<!---
The examples given here are largely taken from the `yacas` 
documentation (especially from the introductory chapter) but are 
organised differently.
--->


# `R` expressions,  `yacas` expressions and `Sym` objects 

The `Ryacas` package works by sending ``commands''
to `yacas` which makes the calculations and returns the result
to `R`. There are various different formats of the return value as well

## `R` expressions

A call to `yacas` may be in the form of an `R` expression which
involves valid R calls, symbols or constants (though not all valid `R` 
expressions are valid). For example:

```{r}
exp1 <- yacas(expression(Factor(x^2-1)))
``` 

The result `exp1` is not an expression in the `R` sense but an
object of class `"yacas"`. 
To evaluate the resulting expression numerically, we can do

```{r}
Eval(exp1, list(x=4))
``` 

## `yacas` expressions

Some commands are not proper `R` expressions. For example, 
typing 
```
yacas(expression(D(x)Sin(x)))
``` 
produces an error. 
For such cases we can make
a specification using the `yacas` syntax:

```{r}
yacas("D(x)Sin(x)")
``` 


## `Sym` objects

Probably the most elegant way of working with `yacas` is by using
`Sym` objects.
A `Sym` object is a `yacas` character string that has the "Sym" class.
One can combine `Sym` objects with other `Sym` objects as well as to
other `R` objects using `+`, `-` and other similar `R` 
operators.

The function `Sym(x)` coerces an object `x` to a `Sym` object by
first coercing it to character and then changing its class to "Sym":

```{r}
x <- Sym("x")
``` 

Operations on `Sym` objects lead to new `Sym` objects:

```{r}
x+4
``` 

One can apply `sin`, `cos`, `tan`, `deriv`, `Integrate`
and other provided functions to `Sym` objects. For example:

```{r}
Integrate(sin(x), x)
``` 
In this way the communication with `yacas` is ``tacit''.

It is important to note the difference between the `R` name `x`
and the symbol `"x"` as illustrated below:

```{r}
x <- Sym("xs")
x
x+4
Eval(x+4, list(xs=5))
``` 

The convention in the following is 1) that `Sym` objects match with
their names that they end with an 's', e.g.

```{r}
xs <- Sym('xs')
``` 


# A sample session

Algebraic calculations:

```{r}
yacas(expression((10 + 2) * 5 + 7^7))
yacas(expression(1/14+5/21* (30- 1+ 1/2)))
``` 


```{r}
#(Sym(10) + Sym(2)) * Sym(5) + Sym(7) ^ Sym(7)
Sym("10 * 2") * 5 + Sym(7) ^ 7
#(Sym(10) + 2) * 5 + Sym(7) ^ 7
#Sym("(10+2)*5 + 7^7")
Sym("1/14 + 5/21 * (30 - 1+1/2)")
``` 


Numerical evaluations:

```{r}
yacas(expression(N(-12/2)))
``` 

```{r}
Sym("-12/2")
#Eval(Sym("-12/2"))
``` 


Symbolic expressions:

```{r}
yacas(expression(Factor(x^2-1)))
exp1 <- expression(x^2 + 2 * x^2)
exp2 <- expression(2 * exp0)
exp3 <- expression(6 * pi * x)
exp4 <- expression((exp1 * (1 - sin(exp3))) / exp2)
yacas(exp4)
``` 


```{r}
Factor(xs^2-1)
exp1 <- xs^2 + 2 * xs^2
exp0 <- Sym("exp0")
exp2 <- 2 * Sym(exp0)
exp3 <- 6 * Pi * xs
exp4 <- exp1 * (1 - sin(exp3)) / exp2
exp4
``` 



Combining symbolic and numerical expressions:

```{r}
yacas(expression(N(Sin(1)^2 + Cos(x)^2)))
``` 


```{r}
N(sin(1)^2 + cos(xs)^2)
``` 


Differentiation:

```{r}
yacas("D(x)Sin(x)")
```


```{r}
deriv(sin(xs), xs)
``` 

Integration: 

```{r}
yacas("Clear(a,b,A,B)")
``` 


```{r}
yacas("Integrate(x,a,b)Sin(x)")
``` 


```{r}
as <- Sym("as")
bs <- Sym("bs")
Integrate(sin(xs), xs, as, bs)
``` 


Expanding polynomials:

```{r}
yacas("Expand((1+x)^3)")
``` 


```{r}
Expand((1+xs)^3)
``` 

Taylor expansion:

```{r}
yacas("texp := Taylor(x,0,3) Exp(x)")
``` 

```{r}
texp <- Taylor(exp(xs), xs, 0, 3)
# Or: texp <- Sym("texp")
``` 


Printing the result in nice forms:

```{r}
yacas("PrettyForm(texp)") 
yacas("TeXForm(texp)")
``` 


```{r}
PrettyForm(texp) 
TeXForm(texp)
``` 



# Simple `yacas` calculations


## Setting and clearing a variable

The function `Set()` and the operator `:=` can both be used to assign
values to global variables. 

```{r}
yacas("n := (10 + 2) * 5")
yacas("n := n+n")
#yacas("Set(z, Cos(a))")
#yacas("z+z")
``` 

The same can be achieved with `Sym` objects: Consider:

```{r}
Set(ns, (10 + 2) * 5)
``` 

Now `ns` exists as a variable in `yacas` (and we
can make computations on this variable as above).
However we have no handle on
this variable in `R`. Such a handle is obtained with

```{r}
ns <- Sym("ns")
``` 
Now the `R` variable `ns` refers to the `yacas` variable
`ns` and we can make  calculations directly from `R`, e.g:

```{r}
Set(ns,123)
ns
ns^2
``` 

Likewise:

```{r}
as <- Sym("as")
zs <- Sym("zs")
Set(zs, cos(as))
zs + zs
``` 


Clear a variable binding execute `Clear()`:

```{r}
yacas(expression(n))
yacas("Clear(n)")
yacas(expression(n))
``` 


```{r}
Set(ns, 1)
ns <- Sym("ns")
ns
Clear(ns)
ns
``` 


## Symbolic and numerical evaluations, precision

Evaluations are generally exact:

```{r}
yacas("Exp(0)")
yacas("Exp(1)")
yacas("Sin(Pi/4)")
yacas("355/113")
``` 


```{r}
exp(Sym(0))
exp(Sym(1))
sin(Pi/4)
Sym("355/113")
``` 

 To obtain a numerical evaluation
(approximation), the `N()` function can be used:

```{r}
yacas("N(Exp(1))")
yacas("N(Sin(Pi/4))")
yacas("N(355/113)")
``` 


```{r}
N(exp(1))
N(sin(Pi/4))
N(355/113)
``` 

The `N()` function has an optional second argument, the required precision:

```{r}
yacas("N(355/133,20)")
``` 


```{r}
N("355/113",20) 
``` 


The command `Precision(n)`
can be used to specify that all floating point numbers should have a
fixed precision of n digits:

```{r}
yacas("Precision(5)")
yacas("N(355/113)")
``` 


```{r}
Precision(5)
N("355/113")
``` 


## Rational numbers

Rational numbers will stay rational as long as the numerator and
denominator are integers:

```{r}
yacas(expression(55/10))
``` 


```{r}
Sym("55 / 10")
``` 


## Symbolic calculation

Some exact manipulations :

```{r}
yacas("1/14+5/21*(30-(1+1/2)*5^2)")
yacas("0+x")
yacas("x+1*y")
yacas("Sin(ArcSin(alpha))+Tan(ArcTan(beta))")
``` 


```{r}
Sym("1/14+5/21*(1*30-(1+1/2)*5^2)")
xs <- Sym("xs")
ys <- Sym("ys")
0+xs
xs+1*ys
sin(asin(xs))+tan(atan(ys))
``` 

## Complex numbers and the imaginary unit

The imaginary unit $i$ is denoted I and complex numbers can be entered
as either expressions involving I or explicitly Complex(a,b) for a+ib.

```{r}
yacas("I^2")
yacas("7+3*I")
yacas("Conjugate(%)")
yacas("Exp(3*I)")
``` 


```{r}
I^2
7+3*I
Conjugate(7+3*I)
exp(3*I)
``` 


## Recall the most recent line -- the `%` operator

The operator `%` automatically recalls the result from the
previous line. 

```{r}
yacas("(1+x)^3")
yacas("%")
yacas("z:= %")
``` 


```{r}
(1+x)^3
zs <- Sym("%")
zs
``` 



## Printing with `PrettyForm`, `PrettyPrint` and `TeXForm`

There are different ways of displaying the output. 


### Standard form

The (standard)
yacas form is:

```{r}
yacas("A:={{a,b},{c,d}}")
yacas("B:= (1+x)^2+k^3")
yacas("A")
yacas("B")
``` 


```{r}
as <- Sym("as"); bs <- Sym("bs"); cs <- Sym("cs"); ds <- Sym("ds")
A <- List(List(as,bs), List(cs,ds))
ks <- Sym("ks")
B <- (1+xs)^2+ks^3
A
B
``` 


### Pretty form

The Pretty form is:

```{r}
yacas("PrettyForm(A)")
yacas("PrettyForm(B)")
``` 


```{r}
PrettyForm(A)
PrettyForm(B)
``` 



### TeX form

The output can be displayed in TeX form:

```{r}
yacas("TeXForm(B)")
``` 


```{r}
TeXForm(B)
``` 


# Commands


## Factorial


```{r}
yacas("40!")
``` 


```{r}
Factorial(40)
``` 

## Taylor expansions

Expand $\exp(x)$ in three terms
around $0$ and $a$:

```{r}
yacas("Taylor(x,0,3) Exp(x)")
yacas("Taylor(x,a,3) Exp(x)")
``` 


```{r}
xs <- Sym("xs")
Taylor(exp(xs),xs,0,3)
as <- Sym("as")
Taylor(exp(x),x,as,3)
``` 

The `InverseTaylor()` function builds the Taylor series expansion of the
inverse of an expression. For example, the Taylor expansion in two
terms of the inverse of $\exp(x)$ around $x=0$ (which is the Taylor
expansion of $Ln(y)$ around $y=1$):

```{r}
yacas("InverseTaylor(x,0,2)Exp(x)")
yacas("Taylor(y,1,2)Ln(y)")
``` 


```{r}
InverseTaylor(exp(xs),xs,0,2)
Taylor(log(ys),ys,1,2)
``` 

## Solving equations


### Solving equations symbolically

Solve equations symbolically with the `Solve()` function:

```{r}
yacas("Solve(x/(1+x) == a, x)")
yacas("Solve(x^2+x == 0, x)")
``` 

```{r}
Solve(xs/(1+xs) == as, xs)
Solve(xs^2+xs == 0, xs)
``` 

```{r}
Solve(List(xs^2+ys^2==6, xs-ys==3), List(xs,ys))
```

```{r}
# FIXME
#Solve(List(mean==(xs/(xs+ys)), variance==((xs*ys)/(((xs+ys)^2) * (xs+ys+1)))),
#    List(xs,ys))
```

(Note the use of the == operator, which does not evaluate to anything,
to denote an "equation" object.) 

### Solving equations numerically

To solve an equation (in one variable) like $sin(x)-exp(x)=0$ numerically taking $0.5$
as initial guess and an accuracy of $0.0001$ do:

```{r}
yacas("Newton(Sin(x)-Exp(x),x, 0.5, 0.0001)")
``` 


```{r}
Newton(sin(xs)-exp(xs),xs, 0.5, 0.0001) 
``` 

## Expanding polynomials

```{r}
yacas(expression(Expand((1+x)^3)))
``` 


```{r}
Expand((x+1)^3)
``` 



## Simplifying an expression

The function Simplify() attempts to reduce an expression
to a simpler form. 

```{r}
y <- Sym("y")
yacas("(x+y)^3-(x-y)^3")
yacas("Simplify(%)")

``` 


```{r}
(x+y)^3-(x-y)^3
Simplify("%")
``` 


## Analytical derivatives

Analytical derivatives of functions can be evaluated with the
`D()` and `deriv()` functions:

```{r}
yacas("D(x) Sin(x)")
``` 


```{r}
deriv(sin(xs), xs)
``` 

These functions also accepts an argument specifying how often the
derivative has to be taken, e.g:

```{r}
yacas("D(x,4)Sin(x)")
``` 


```{r}
deriv(sin(xs),xs,4)
``` 

## Integration

@ 
<<echo=F,results=hide>>=
yacas("Clear(a,b,A,B)")
``` 


```{r}
#yacas("Integrate(x,a,b)Sin(x)")
#yacas("Integrate(x,a,b)Ln(x)+x")
#yacas("Integrate(x)1/(x^2-1)")
yacas("Integrate(x)Sin(a*x)^2*Cos(b*x)")
``` 


```{r}
#Integrate(sin(x),x,a,b)
#Integrate(log(x),x,a,b)
#Integrate(1/(x^2-1),x)
a <- Sym("a")
b <- Sym("b")
Integrate(sin(a*x)^2*cos(b*x),x)
``` 


## Limits

```{r}
#yacas("Limit(x,0)Sin(x)/x")
yacas("Limit(n,Infinity)(1+(1/n))^n")
yacas("Limit(h,0) (Sin(x+h)-Sin(x))/h")
``` 


```{r}
#Limit(sin(x)/x,x,0)
ns <- Sym("ns")
Limit((1+(1/ns))^ns,ns,Infinity)
hs <- Sym("hs")
Limit((sin(xs+hs)-sin(xs))/hs,hs,0)
``` 

## Variable substitution


```{r}
yacas("Subst(x,Cos(a))x+x")
``` 


```{r}
Subst(xs+xs,xs,cos(as))
``` 

## Solving ordinary differential equations


```{r}
yacas("OdeSolve(y''==4*y)")
yacas("OdeSolve(y'==8*y)")
``` 








# Matrices


```{r}
yacas("E4:={ {u1,u1,0},{u1,0,u2},{0,u2,0} }")
yacas("PrettyForm(E4)")
``` 


```{r}
u1 <- Sym("u1")
u2 <- Sym("u2")
E4 <- List(List(u1, u1, 0), List(u1, 0, u2), List(0, u2, 0))
PrettyForm(E4)
``` 


## Inverse


```{r}
yacas("E4i := Inverse(E4)")
yacas("Simplify(E4i)")
yacas("PrettyForm(Simplify(E4i))")
``` 



```{r}
E4i <- Inverse(E4)
Simplify(E4i)
PrettyForm(Simplify(E4i))
``` 


## Determinant


```{r}
yacas("Determinant(E4)")
yacas("Determinant(E4i)")
yacas("Simplify(E4i)")
yacas("Simplify(Determinant(E4i))")
``` 



```{r}
determinant(E4)
determinant(E4i)
Simplify(E4i)
Simplify(determinant(E4i))
``` 



# Miscellaneous


Note that the value returned by `yacas` can be of different types:

```{r}
yacas(expression(Factor(x^2-1)),retclass='unquote')
yacas(expression(Factor(x^2-1)),retclass='character')
``` 

# Output width


Set output width:

```{r}
get_output_width()
set_output_width(120)
get_output_width()
```

