- Metaprogramming is used to write code at parsing time in order to help the compiler achieve good performance
- Metaprogramming is used to write Domain-Specific Languages (DSLs) to make easy syntax for complicated functions

`@fastmath 3*5`

- ParallelAccelerator's
`@acc`

`@simd`

`@parallel`

`Threads.@threads`

- Even DSLs will use symbolic mathematics to automatically simplify a problem for you!

`~`

for Formulas was actually in in-place macro!

For differential equations packages, the standard way to define a differential equation like the Lorenz equation:

$$ \begin{align} x\prime &= \sigma (y-x)\\ y\prime &= x (\rho - z) - y\\ z\prime &= xy - \beta z\\ \end{align} $$

is the following:

In [ ]:

```
f = (du,u,p,t) -> begin
σ, ρ, β = p
du[1] = σ*(u[2]-u[1])
du[2] = u[1]*(ρ-u[3]) - u[2]
du[3] = u[1]*u[2] - β*u[3]
end
```

However, we can define a DSL to make this easier to do:

In [ ]:

```
g = @ode_def begin
dx = σ*(y-x)
dy = x*(ρ-z) - y
dz = x*y - β*z
end σ ρ β
```

JuMP has a DSL which allows you to define constrainted optimization problems without reference to the package or type of equation which is being solved. You can then swap out different optimization packages to use as the solver without care.

In [ ]:

```
using JuMP
m = Model()
@variable(m, 0 <= x <= 2 )
@variable(m, 0 <= y <= 30 )
@objective(m, Max, 5x + 3*y )
@constraint(m, 1x + 5y <= 3.0 )
print(m)
status = solve(m)
println("Objective value: ", getobjectivevalue(m))
println("x = ", getvalue(x))
println("y = ", getvalue(y))
```

An easy way to write macros is the "QuoteLater" method:

- Write a macro, make it work (in the REPL)
- Later, quote it and interpolate in the value

The Julia manual is very complete on Metaprogramming: http://docs.julialang.org/en/release-0.5/manual/metaprogramming/

One fact that it misses: How to interpolate an expression as an expression (not as a value) into another expression.

In [ ]:

```
ex_new = Meta.quot(ex)
quote
still_expression = $(esc(ex_new))
end
```

You have a way to compute least squares, how about letting it work like an `R`

function? Define your own version `solve_least_squares(Y,X)`

using your previous result, and define the `@~`

macro so that way `solve_least_squares(Y~1+X1+X2+X4)`

solves the least square problem on the data matrix `X`

on its columns 1, 2, and 4.

Metaprogramming is hard the first few times you do it. You might want to work in pairs!

Hints:

- You cannot "get a character" from a symbol
- You can use
`string`

to change a symbol to a string - You can
`parse`

a string to a number - Check out the
`args`

field of an expression: it's an array that holds a bunch of goodies!

In [ ]:

```
y = rand(10)
X = rand(10,4)
y~1+X1+X2+X4 # Make a tuple
solve_least_squares(y~1+X1+X2+X4) # Solve the least square problem on a tuple
```