# Lecture 38: Introduction to Julia¶

Julia is a programming language which aims to combine the high productivity of scripting languages with the high performance of compiled languages. The paper [BEKS17] describes the language.

## Getting Started¶

In the cloud, at CoCalc: https://cocalc.com you can open a Jupyter notebook with a Julia kernel.

To install Julia on your own computer, follow the instructions
at <https://julialang.org>. To execute Julia programs in a Jupyter notebook,
do `using IJulia`

followed by `notebook()`

in the REPL of Julia,
that is: when running in a Terminal or PowerShell window.
With `using`

one can install `Plots`

, `SymPy`

and `Symbolics`

.
The `SymPy.jl`

is a wrapper to the Python package `SymPy`

,
whereas `Symbolics`

[GMCGSER22] is a computer algebra system
written in Julia.

To demonstrate symbolic computation with Julia, consider the problem of computing the slope of the tangent line at a point on a circle.

## Implicit Differentiation with SymPy.jl¶

In the equation of the circle \(x^2 + y^2 - 1 = 0\), the variable \(x\) is the independent variable and the variable \(y\) depends on \(x\). We will obtain the slope via implicit differentiation, as \(\displaystyle \frac{d}{d~\!x} y(x)\).

```
using SymPy
```

If `SymPy`

is not yet installed, then you will be prompted to install.

The declarations of the variables result in `dy`

to be assigned the
unknown slope \(\displaystyle \frac{d}{d~\!x} y(x)\).

```
x = Sym("x")
y = SymFunction("y")
dy = diff(y(x), x)
```

Observe that `y`

is declared as a symbolic function,
in *any* symbol. If we want to use `y`

when we define
the equation, then we *must* use `y(x)`

to indicate that
the function `y`

depends on `x`

.

```
c = x^2 + y(x)^2 - 1
dc = diff(c, x)
dydx = solve(dc, dy)
```

The `solve`

returns an `Array`

which starts in Julia with index one.
The slope is then obtained as

```
symbolicslope = dydx[1]
```

and equals `-x/y(x)`

.

Let us now take a random point on the circle, generated by a random angle, using the polar representation.

```
angle = 2*pi*rand()
(a, b) = (cos(angle), sin(angle))
sd = Dict(x => a, y(x) => b)
```

The coordinates of the point `(a, b)`

are stored in a dictionary,
which is a convenient data structure for substitution.
Observe that, as Julia is geared towards numerical computing,
the `pi`

is a 64-bit floating-point approximation for \(\pi\).
The numerical value for the slope is then obtained via substitution
as follows:

```
slope = symbolicslope.subs(sd)
```

The numerical value in `slope`

serves as a reference to check
the alternative computation of the slope via the Taylor series.

The `series`

of `SymPy`

works for one variable only,
but it works well on purely symbolic expressions, so we can compute
the expression for the tangent line by running `series`

twice.
Because we continue the session, we declare new symbols `X`

and `Y`

for the variables in the circle equation and `A`

and `B`

for the
coordinates of the point.

```
X, Y, A, B = Sym("X, Y, A, B")
nc = X^2 + Y^2 - 1
cx = SymPy.series(nc, X, A, 2)
```

In `cx`

is the Taylor series expansion of the expression
stored in `nc`

about `X = A`

, of order `2`

.
To convert the `cx`

into a symbolic expression on which
we can apply `series`

again, we select the coefficient
to make the expression `px`

(a polynomial as truncated series).

```
px = cx.coeff(X, 0) + cx.coeff(X - A, 1)*(X - A)
cy = series(px, Y, B, 2)
cY = cy.subs(Dict(A => a, B => b)
```

Then the slope is obtained as

```
- cY.coeff(X, 1)/cY.coeff(Y, 1)
```

which agrees with the value earlier assigned to `slope`

.

## Implicit Differentiation with Symbolics.jl¶

We will now compute the value of the slope a third time.

```
using Symbolics.jl
@variables x, y(x)
```

Observe that with `Symbolics`

(opposite to what we did with `SymPy`

),
we declare `y(x)`

so `y`

is explicitly defined as depending on `y`

.
This implies that typing `y`

suffices and, unlike with `SymPy`

,
we do not need to type `y(x)`

when we define the equation of the circle.

In order not to confuse with the `Differential`

of `SymPy`

,
which we used earlier in this notebook,
we declare that we use the `Differential`

of `Symbolics`

.

```
D = Symbolics.Differential(x)
dy = D(y)
```

As before, `dy`

is \(\displaystyle \frac{d}{d~\!x} y(x)\).

```
c = x^2 + y^2 - 1
dc = D(c)
```

The differential operator `D`

does not expand automatically,
we have to ask for it.

```
eq = expand_derivatives(dc)
SBslope = Symbolics.solve_for(eq,dx)
```

In `SBslope`

is the expression `-x/y(x)`

so the symbolic part of this problem is thus indeed solved.
What is left is the substitution, again using a dictionary,
mapping the coordinates `(a, b)`

of the random point
to the symbols `x`

and `y`

.

```
nsd = Dict(x => a, y => b)
substitute(SBslope, nsd)
```

and we see again the value that was earlier assigned
to `slope`

.

References

J. Bezanson, A. Edelman, S. Karpinski, V.B. Shah.
A fresh approach to numerical computing.
*SIAM Review* 59(1): 65-98, 2017.

S. Gowda, Y. Ma, A. Cheli, M. Gwozdz, V.B. Shah,
A. Edelman, and C. Rackauckas.
*High-performance symbolic-numerics via multiple dispatch*,
arxiv:2105.03949v3 [cs.CL] 5 Feb 2022.