# ------------------------------------------------------------------------------------------
# # 矩阵分解与其他妙用
# 该教程由Andreas Noack所做的工作改编而成
#
# ## 大纲
#  - 矩阵分解
#  - 特殊矩阵
#  - 一般化线性代数
# ------------------------------------------------------------------------------------------

# ------------------------------------------------------------------------------------------
# 正式开始之前，让我们先来建立一个线性系统，并利用`LinearAlgebra`库来进行矩阵分解或处理特殊矩阵。
# ------------------------------------------------------------------------------------------

using LinearAlgebra
A = rand(3, 3)
x = fill(1, (3,))
b = A * x

# ------------------------------------------------------------------------------------------
# ## 矩阵分解
#
# #### LU分解
# 在Julia中，我们可以使用`lufact`进行LU分解：
# ```julia
# PA = LU
# ```
# 其中`P`是置换矩阵，`L`是对角全为1的下三角矩阵（单位下三角矩阵），`U`是上三角矩阵。
#
# Julia可以计算LU分解，并定义一个复合分解数据类型用以储存分解后的结果。
# ------------------------------------------------------------------------------------------

Alu = lu(A)

typeof(Alu)

# ------------------------------------------------------------------------------------------
# 可以通过这个类的特殊属性来调取分解出来的矩阵：
# ------------------------------------------------------------------------------------------

Alu.P

Alu.L

Alu.U

# ------------------------------------------------------------------------------------------
# Julia可以对储存分解结果的对象派发方法。
#
# 比如，在解算当前的线性系统时，我们既可以使用原本的矩阵，也可以使用分解运算所生成的对象：
# ------------------------------------------------------------------------------------------

A\b

Alu\b

# ------------------------------------------------------------------------------------------
# 相似地，要计算矩阵`A`的行列式，既可以使用原本的矩阵，也可以使用分解运算所生成的对象：
# ------------------------------------------------------------------------------------------

det(A) ≈ det(Alu)

# ------------------------------------------------------------------------------------------
# #### QR分解
#
# 在Julia中，可以使用`qrfact`来计算QR分解：
# ```
# A=QR
# ```
#
# 其中`Q`是正交阵/酉矩阵，`R`是上三角矩阵。
# ------------------------------------------------------------------------------------------

Aqr = qr(A)

# ------------------------------------------------------------------------------------------
# 与LU分解类似，矩阵`Q`和`R`可以通过以下语句从QR分解对象中调取：
# ------------------------------------------------------------------------------------------

Aqr.Q

Aqr.R

# ------------------------------------------------------------------------------------------
# #### 特征分解
# ------------------------------------------------------------------------------------------

# ------------------------------------------------------------------------------------------
# 特征分解、奇异值分解（SVD）、Hessenberg分解、Schur分解的结果都是以`Factorization`类型来储存的。
#
# 以下语句可用于计算特征值：
# ------------------------------------------------------------------------------------------

Asym = A + A'
AsymEig = eigen(Asym)

# ------------------------------------------------------------------------------------------
# 通过特殊索引，可以从Eigen类型中提取计算得到的特征值和特征向量：
# ------------------------------------------------------------------------------------------

AsymEig.values

AsymEig.vectors

# ------------------------------------------------------------------------------------------
# 再一次地，当分解结果被储存为特定的类型时，我们可以对它使用派发方法，也可以编写一些具有针对性的方法以充分利用矩阵分解的性质。例如，$A^{-1}=(V\Lambda
# V^{-1})^{-1}=V\Lambda^{-1}V^{-1}$。
# ------------------------------------------------------------------------------------------

inv(AsymEig)*Asym

# ------------------------------------------------------------------------------------------
# ## 特殊矩阵结构
# 矩阵结构在线性代数中有着尤为重要的作用。让我们通过一个大型线性系统来看看它到底有*多重要*吧：
# ------------------------------------------------------------------------------------------

n = 1000
A = randn(n,n);

# ------------------------------------------------------------------------------------------
# 通常，Julia可以自动推断出特殊矩阵结构：
# ------------------------------------------------------------------------------------------

Asym = A + A'
issymmetric(Asym)

# ------------------------------------------------------------------------------------------
# 但有时浮点误差会阻碍这一功能：
# ------------------------------------------------------------------------------------------

Asym_noisy = copy(Asym)
Asym_noisy[1,2] += 5eps()

issymmetric(Asym_noisy)

# ------------------------------------------------------------------------------------------
# 幸运的是，我们可以使用`Diagonal`（对角）、`Triangular`（三角）、`Symmetric`（对称）、`Hermitian`（厄米/自共轭矩阵）、`Tridiago
# nal`（三对角）、`SymTridiagonal`（对称三对角）等函数显式地定义特殊矩阵。
# ------------------------------------------------------------------------------------------

Asym_explicit = Symmetric(Asym_noisy);

# ------------------------------------------------------------------------------------------
# 现在，我们来比较Julia在计算`Asym`、`Asym_noisy`和`Asym_explicit`的特征值时各自需要多长时间：
# ------------------------------------------------------------------------------------------

@time eigvals(Asym);

@time eigvals(Asym_noisy);

@time eigvals(Asym_explicit);

# ------------------------------------------------------------------------------------------
# 在这个示例中，对`Asym_noisy`使用`Symmetric()`使得我们的运算效率提高了`5倍` :)
# ------------------------------------------------------------------------------------------

# ------------------------------------------------------------------------------------------
# #### 一个“大”问题
# 用`Tridiagonal`和`SymTridiagonal`类型储存三对角矩阵让我们得以处理有可能非常庞大的三对角问题。对于下面的示例问题而言，如果矩阵被储存为一个（稠密的）`M
# atrix`类型，那么一台笔记本电脑的配置将会不足以支持该问题的解算。
# ------------------------------------------------------------------------------------------

n = 1_000_000;
A = SymTridiagonal(randn(n), randn(n-1));
@time eigmax(A)

# ------------------------------------------------------------------------------------------
# ## 一般化线性代数
# 要在语言中添加对数值化的线性代数的支持，常规的手段是包装BLAS和LAPACK中的子程序。对于含有`Float32`、`Float64`、`Complex{Float32}`或`C
# omplex{Float64}`等类型的元素的矩阵，这正是Julia的处理方式。
#
# 然而，Julia也支持一般化的线性代数。运用这一特性的其中一个例子便是处理有理数矩阵和向量。
# ------------------------------------------------------------------------------------------

# ------------------------------------------------------------------------------------------
# #### 有理数
# Julia内嵌有对有理数的支持。使用双斜杠以构建一个有理数：
# ------------------------------------------------------------------------------------------

1//2

# ------------------------------------------------------------------------------------------
# #### 示例：有理数线性方程组
# 下面的例子将会演示如何在不将矩阵元素转化为浮点类型的前提下求解一个含有有理数的线性方程组。在处理有理数时，数值溢出很容易成为一个问题，因此我们使用`BigInt`类型：
# ------------------------------------------------------------------------------------------

Arational = Matrix{Rational{BigInt}}(rand(1:10, 3, 3))/10

x = fill(1, 3)
b = Arational*x

Arational\b

lu(Arational)

# ------------------------------------------------------------------------------------------
# ### 练习
#
# #### 11.1
# 求解矩阵A的特征值
#
# ```
# A =
# [
#  140   97   74  168  131
#   97  106   89  131   36
#   74   89  152  144   71
#  168  131  144   54  142
#  131   36   71  142   36
# ]
# ```
# 并将它赋给变量`A_eigv`。
# ------------------------------------------------------------------------------------------

using LinearAlgebra

@assert A_eigv ==  [-128.49322764802145, -55.887784553056875, 42.7521672793189, 87.16111477514521, 542.4677301466143]

# ------------------------------------------------------------------------------------------
# #### 11.2
# 由`A`的特征值构建一个`Diagonal`（对角）矩阵。
# ------------------------------------------------------------------------------------------

@assert A_diag ==  [-128.493    0.0      0.0      0.0       0.0;
    0.0    -55.8878   0.0      0.0       0.0;
    0.0      0.0     42.7522   0.0       0.0;
    0.0      0.0      0.0     87.1611    0.0;
    0.0 0.0      0.0      0.0     542.468]

# ------------------------------------------------------------------------------------------
# #### 11.3
# 由`A`构建一个`LowerTriangular`（下三角）矩阵，并将其储存为`A_lowertri`。
# ------------------------------------------------------------------------------------------

@assert A_lowertri ==  [140    0    0    0   0;
  97  106    0    0   0;
  74   89  152    0   0;
 168  131  144   54   0;
 131   36   71  142  36]

# ------------------------------------------------------------------------------------------
# ### 反馈与评价（英文）：
# https://tinyurl.com/introJuliaFeedback
# ------------------------------------------------------------------------------------------

# ------------------------------------------------------------------------------------------
# 完成练习后请点击顶部的`Validate`按钮。
# ------------------------------------------------------------------------------------------


using Test
using FinancialToolbox, DualNumbers

#Test Parameters
testToll = 1e-14;

#print_colored("Starting Standard Test\n",:green)
spot = 10;
K = 10;
r = 0.02;
T = 2.0;
sigma = 0.2;
d = 0.01;
spotDual = dual(spot, 1.0);

toll = 1e-6

#EuropeanCall Option
PriceCall = blsprice(spot, K, r, T, sigma, d);
PriceCallBlack = blkprice(spot, K, r, T, sigma);

df(f, x, dx) = (f(x + dx) - f(x)) / dx
dx = 1e-8;
assert_(value, toll) = @test abs(value) < toll

sigma1 = blsimpv(spot, K, r, T, PriceCall, d);
ResDual = blsimpv(spotDual, K, r, T, PriceCall, d);
DerDF_ = df(spot -> blsimpv(spot, K, r, T, PriceCall, d), spot, dx);

assert_(sigma1 - ResDual, toll)
assert_(DerDF_ - ResDual.epsilon, toll)

sigma1 = blkimpv(spot, K, r, T, PriceCallBlack);
ResDual = blkimpv(spotDual, K, r, T, PriceCallBlack);
DerDF_ = df(spot -> blkimpv(spot, K, r, T, PriceCallBlack), spot, dx);

assert_(sigma1 - ResDual, toll)
assert_(DerDF_ - ResDual.epsilon, toll)

print_colored("Starting DualNumbers Test\n", :green)

#Test Parameters
testToll = 1e-14;
spot = 10;
K = 10;
r = 0.02;
T = 2.0;
sigma = 0.2;
d = 0.01;

#EuropeanCall Option
PriceCall = blsprice(spot, K, r, T, sigma, d);
DeltaCall = blsdelta(spot, K, r, T, sigma, d);
ThetaCall = blstheta(spot, K, r, T, sigma, d);
RhoCall = blsrho(spot, K, r, T, sigma, d);
LambdaCall = blslambda(spot, K, r, T, sigma, d);
VannaCall = blsvanna(spot, K, r, T, sigma, d);

#EuropeanPut Option
PricePut = blsprice(spot, K, r, T, sigma, d, false);
DeltaPut = blsdelta(spot, K, r, T, sigma, d, false);
ThetaPut = blstheta(spot, K, r, T, sigma, d, false);
RhoPut = blsrho(spot, K, r, T, sigma, d, false);
LambdaPut = blslambda(spot, K, r, T, sigma, d, false);
VannaPut = blsvanna(spot, K, r, T, sigma, d, false);

#Equals for both Options
Gamma = blsgamma(spot, K, r, T, sigma, d);
Vega = blsvega(spot, K, r, T, sigma, d);

########DUAL NUMBERS
DerToll = 1e-13;
#Function definition
#Call
FcallDual(spot) = blsprice(spot, K, r, T, sigma, d);
GcallDual(r) = blsprice(spot, K, r, T, sigma, d);
HcallDual(T) = blsprice(spot, K, r, T, sigma, d);
LcallDual(sigma) = blsprice(spot, K, r, T, sigma, d);
PcallDual(spot) = blsprice(spot, K, r, T, sigma, d) * spot.value / blsprice(spot.value, K, r, T, sigma, d);
VcallDual(sigma) = blsdelta(spot, K, r, T, sigma, d);
#Put
FputDual(spot) = blsprice(spot, K, r, T, sigma, d, false);
GputDual(r) = blsprice(spot, K, r, T, sigma, d, false);
HputDual(T) = blsprice(spot, K, r, T, sigma, d, false);
PputDual(spot) = blsprice(spot, K, r, T, sigma, d, false) * spot.value / blsprice(spot.value, K, r, T, sigma, d, false);
VPutDual(sigma) = blsdelta(spot, K, r, T, sigma, d, false);
#Input
SpotDual = Dual(spot, 1.0);
rDual = Dual(r, 1.0);
TDual = Dual(T, 1.0);
SigmaDual = Dual(sigma, 1.0);

#Automatic Differentiation Test
#TEST
print_colored("--- European Call Sensitivities: DualNumbers\n", :yellow)
print_colored("-----Testing Delta\n", :blue);
assert_(FcallDual(SpotDual).epsilon - DeltaCall, DerToll)
print_colored("-----Testing Rho\n", :blue);
assert_(GcallDual(rDual).epsilon - RhoCall, DerToll)
print_colored("-----Testing Theta\n", :blue);
assert_(-HcallDual(TDual).epsilon - ThetaCall, DerToll)
print_colored("-----Testing Lambda\n", :blue);
assert_(PcallDual(SpotDual).epsilon - LambdaCall, DerToll)
print_colored("-----Testing Vanna\n", :blue);
assert_(VcallDual(SigmaDual).epsilon - VannaCall, DerToll)
#TEST
print_colored("--- European Put Sensitivities: DualNumbers\n", :yellow)
print_colored("-----Testing Delta\n", :blue);
assert_(FputDual(SpotDual).epsilon - DeltaPut, DerToll)
print_colored("-----Testing Rho\n", :blue);
assert_(GputDual(rDual).epsilon - RhoPut, DerToll)
print_colored("-----Testing Theta\n", :blue);
assert_(-HputDual(TDual).epsilon - ThetaPut, DerToll)
print_colored("-----Testing Lambda\n", :blue);
assert_(PputDual(SpotDual).epsilon - LambdaPut, DerToll)
print_colored("-----Testing Vanna\n", :blue);
assert_(VPutDual(SigmaDual).epsilon - VannaPut, DerToll)

print_colored("-----Testing Vega\n", :blue);
assert_(LcallDual(SigmaDual).epsilon - Vega, DerToll)
print_colored("Dual Numbers Test Passed\n", :green)
println("")

#TEST OF INPUT VALIDATION
print_colored("Starting Input Validation Test Dual\n", :magenta)
print_colored("----Testing Negative  Spot Price \n", :cyan)
@test_throws(ErrorException, blsprice(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blkprice(-SpotDual, K, r, T, sigma))
@test_throws(ErrorException, blsdelta(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blsgamma(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blstheta(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blsrho(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blspsi(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blslambda(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blsvanna(-SpotDual, K, r, T, sigma, d))
@test_throws(ErrorException, blsvega(-SpotDual, K, r, T, sigma, d))

print_colored("----Testing Negative  Strike Price \n", :cyan)
KK = Dual(K, 0);
@test_throws(ErrorException, blsprice(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blkprice(spot, -KK, r, T, sigma))
@test_throws(ErrorException, blsdelta(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blsgamma(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blstheta(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blsrho(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blspsi(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blslambda(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blsvanna(spot, -KK, r, T, sigma, d))
@test_throws(ErrorException, blsvega(spot, -KK, r, T, sigma, d))

print_colored("----Testing Negative  Time to Maturity \n", :cyan)
@test_throws(ErrorException, blsprice(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blkprice(spot, K, r, -TDual, sigma))
@test_throws(ErrorException, blsdelta(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blsgamma(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blstheta(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blsrho(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blspsi(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blslambda(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blsvanna(spot, K, r, -TDual, sigma, d))
@test_throws(ErrorException, blsvega(spot, K, r, -TDual, sigma, d))

print_colored("----Testing Negative  Volatility \n", :cyan)
@test_throws(ErrorException, blsprice(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blkprice(spot, K, r, T, -SigmaDual))
@test_throws(ErrorException, blsdelta(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blsgamma(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blstheta(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blsrho(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blspsi(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blslambda(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blsvanna(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blsvega(spot, K, r, T, -SigmaDual, d))
@test_throws(ErrorException, blsimpv(spotDual, K, r, T, -0.2, d))

print_colored("Dual Input Validation Test Passed\n", :magenta)


module GellMannMatrices

using LinearAlgebra, SparseArrays
export gellmann

# ---------------------------------------------------------------------------------------- #
# direct sum (i.e., block-diagonalization of matrices As)
if VERSION < v"1.8"
    # work around for https://github.com/JuliaLang/julia/pull/44211 for Julia ≤ v1.7
    @inline ⊕(As...) = cat(As..., dims=(1,2))::typeof((.+)(As...))
else
    @inline ⊕(As...) = cat(As..., dims=Val((1,2)))
end

# https://en.wikipedia.org/wiki/Matrix_unit
unit(::Type{<:SparseMatrixCSC}, i, j, n, m) = sparse([i], [j], [1], n, m)
unit(T::Type{<:AbstractMatrix}, i, j, n, m) = (A = zeros(eltype(T), n, m); A[i,j] = one(eltype(T)); A)

# ---------------------------------------------------------------------------------------- #
# implementation following https://en.wikipedia.org/wiki/Generalizations_of_Pauli_matrices

# off-diagonal matrices (f_ij on Wiki)
function offdiag_gellmann(T::Type{<:AbstractMatrix}, i, j, d)
    if i < j
        return unit(T, i, j, d, d) + unit(T, j, i, d, d)
    elseif i > j
        return -1im * (unit(T, j, i, d, d) - unit(T, i, j, d, d))
    else
        throw(DomainError((j, i), "i and j must differ"))
    end
end

# "diagonal"-like matrices (h_i on Wiki)
function diag_gellmann(T::Type{<:AbstractMatrix}, i, d; norm_identity::Bool=false)
    if i == 1
        return norm_identity ? T(I(d) / sqrt(d/2)) : T(I(d))
    elseif i < d
        return diag_gellmann(T, i, d-1) ⊕ zero(eltype(T))
    elseif i == d
        return sqrt(2/(d*(d-1))) * (T(I(d-1)) ⊕ convert(eltype(T), (1-d)))
    else
        throw(DomainError((i,d), "invalid combination of (i,d); must have i ≤ d and d ≥ 1"))
    end
end

# ---------------------------------------------------------------------------------------- #

"""
    gellmann([T::Type{<:AbstractMatrix}=Matrix{ComplexF64},] d::Integer; skip_identity=true)

Return the generalized Gell-Mann matrices in `d` dimensions as a vector of matrices of type
`T`.

`T` can be any mutable `AbstractMatrix`, including `SparseMatrixCSC`, with complex floating
point element type.

## Keyword arguments
- `skip_identity` (default, `true`): if `false`, the identity matrix of dimension `d` is
  included as the last element of the returned vector.
- `norm_identity` (default, `false`): if `true`, the elements of the identity are normalized
   by `sqrt(D/2)` to ensure the the orthogonality relation `tr(A'*A) = 2`.

## Examples
Compute the Pauli matrices ``σ_i`` (`d=2`) and Gell-Mann matrices ``Λ_i`` (`d=3`):
```jl
julia> σᵢ = gellmann(2)
julia> Λᵢ = gellmann(3)
```
"""
gellmann(d::Integer; kwargs...) = gellmann(Matrix{ComplexF64}, d; kwargs...)

function gellmann(T::Type{<:AbstractMatrix}, d::Integer;
                  skip_identity=true, norm_identity=false)
    d > 0 || throw(DomainError(d, "dimension must be a positive integer"))
    eltype(T) == complex(eltype(T)) || throw(DomainError(T, "the element type of T must be complex"))
    # we collect the matrices in the slightly odd-looking manner below in order to be
    # consistent with the conventional number of Pauli and Gell-Mann matrices.
    ms = Vector{T}(undef, d*d - skip_identity)
    k = 0
    for i in 2:d
        for  j in 1:i-1
            ms[k+=1] = offdiag_gellmann(T, j, i, d)
            ms[k+=1] = offdiag_gellmann(T, i, j, d)
        end
        ms[k+=1] = diag_gellmann(T, i, d)
    end
    skip_identity || (ms[k+=1] = diag_gellmann(T, 1, d; norm_identity))
    return ms
end

end


# p38.jl - solve u_xxxx = exp(x), u(-1)=u(1)=u'(-1)=u'(1)=0
#         (compare p13.jl)

# Construct discrete biharmonic operator:
N = 15; (D,x) = cheb(N);
S = diagm([0; 1 ./(1-x[2:N].^2); 0]);
D4 = (diagm(1-x.^2)*D^4 - 8*diagm(x)*D^3 - 12*D^2)*S;
D4 = D4[2:N,2:N];

# Solve boundary-value problem and plot result:
f = @. exp(x[2:N]); u = D4\f; u = [0;u;0];
clf(); axes([.1,.4,.8,.5]);
plot(x,u,".",markersize=10);
axis([-1,1,-.01,.06]); grid(true);
xx = (-1:.01:1);
uu = (1-xx.^2).*polyval(polyfit(x,S*u),xx);
plot(xx,uu);

# Determine exact solution and print maximum error:
A = [1 -1 1 -1; 0 1 -2 3; 1 1 1 1; 0 1 2 3];
V = xx.^(0:3)';
c = A\exp.([-1,-1,1,1]); exact = exp.(xx) - V*c;
title("max err = $(signif(norm(uu-exact,Inf),5))",fontsize=12);


"""
Gray Code Generator
===================

## References

- [knuth]: The Art of Computer Programming, Volume 4 Fascicle 2A, 7.2.1.1 Generating all n-tuples.
- [manber]: Introduction to Algorithms: A Creative Approach, 2.9 Gray Codes.
- [wiki]: https://en.wikipedia.org/wiki/Gray_code#Constructing_an_n-bit_Gray_code
"""
module GrayCode

# From [wiki]:
#
# "Once a binary number appears in $G_n$ it appears in the same position in all longer lists; so it
# makes sense to talk about the reflective Gray code value of a number."
#
# "These characteristics suggest a simple and fast method of translating a binary value into the
# corresponding Gray code. Each bit is inverted if the next higher bit of the input value is set to
# one."
#
# From [knuth]:
#
# "[R]eversing the order of Gray binary code is equivalent to complementing the fist bit."
#
# - - - -
#
# We have
#
#     g(i) = b(i) ⊕ b(i + 1)
#
# So g(i) of the MSbit is b(i) as b(i + 1) is 0. And for converting from Gray code to binary
# (c.f. https://math.stackexchange.com/a/1829662):
#
#     b(i) = g(i) ⊕ b(i + 1)
#
# or,
#
#     b(i) = g(i) ⊕ g(i + 1) ⊕ g(i + 2) ⊕ ...

#===== Gray code <-> Binary =====#

# b -> g  (n-th is 1-based)
"Computes the `n`-th reflective gray code."
function gray_nth(n::Integer)::Vector{Int8}
    @assert n > 0
    n -= 1
    g = xor(n, n >>> 1)
    digits(Int8, g, base=2)
end

# g -> b
function gray_to_binary(g::Vector{Int8})::Vector{Int8}
    b = copy(g)
    for i in (length(g) - 1):-1:1
        b[i] = xor(g[i], b[i + 1])
    end
    b
end

#===== Constructs Gray code by recursion =====#

# A slow implementation, just for proof-of-concept. See [manber].
function gray_codes_of_len(len::Integer)::Vector{Vector{Int8}}
    @assert iseven(len) "Gray code of odd length does not exist."
    @assert len > 0 "Length should be greater than 0."
    gray_codes_of_len_r(len)
end

function gray_codes_of_len_r(len::Integer)::Vector{Vector{Int8}}
    if len == 0
        return [[]]
    elseif len == 2
        g =
        [
            Int8[0],
            Int8[1],
        ]
        return g
    end

    if isodd(len)
        _2k = len - 1
        g_2k = gray_codes_of_len_r(_2k)
        if ispow2(_2k)
            g =
            [
                [[0; g] for g in g_2k]...,
                [1; g_2k[end]],
            ]
            return g
        else
            # There are some unused strings of length `ceil(log2(k * 2))`, one of which is connected
            # to one of the used strings.

            # Oops, this construction is useful for the proof but cannot be elegantly expressed as
            # code.
            len_pow2 = nextpow(2, _2k)
            g_pow2 = gray_codes_of_len_r(len_pow2)  # slow, fvck
            used = Set(g_2k)
            for (s, t) in [(i, mod1(i + 1, len_pow2)) for i in 1:len_pow2]
                if g_pow2[s] in used && !(g_pow2[t] in used)
                    index_2k = findfirst(x -> x == g_pow2[s], g_2k)
                    g =
                    [
                        g_2k[(index_2k + 1):end]
                        g_2k[1:index_2k]
                        [g_pow2[t]]
                    ]
                    return g
                end
            end
            error("Should not reach here.")
        end
    end

    half_len = div(len, 2)
    g_half = gray_codes_of_len_r(half_len)
    g_half_rev = reverse(g_half)

    [
        [[0; g] for g in g_half];
        [[1; g] for g in g_half_rev];
    ]
end

#===== Gray code iterating =====#

# c.f. [knuth] Algorithm G.
mutable struct GrayCodeIter
    n::Int
    code::Union{UInt128, Nothing}
    parity::Int8

    GrayCodeIter(n::Int) = new(n, 0, 0)
end

function Base.iterate(iter::GrayCodeIter, state=iter)
    if iter.code == nothing
        nothing
    else
        curr_code = iter.code
        iter.parity ⊻= 1
        if iter.parity == 1
            iter.code ⊻= 1
        elseif iter.code == 1 << (iter.n - 1)
            iter.code = nothing
        else
            iter.code ⊻= curr_code ⊻ (curr_code - 1) + 1
        end
        (curr_code, iter)
    end
end

Base.length(iter::GrayCodeIter) = UInt128(2) ^ iter.n

# TODO: [knuth] Fig. 14

#===== Unit Tests =====#
using Test
using Random: seed!

# Helpers for testing
function diff_one(a::Vector{T}, b::Vector{T})::Bool where T<:Integer
    len_diff = length(a) - length(b)
    if len_diff == 0
        return sum(xor.(a, b)) == 1
    elseif len_diff == 1
        # does nothing
    elseif len_diff == -1
        a, b = b, a
    else
        return false
    end

    a[end] == 1 && @view(a[1:(end - 1)]) == b
end

function binary_array_to_value(ba::Vector{Int8})::UInt64
    @assert length(ba) <= 64
    reduce((acc, x) -> (acc << 1) + x, @view ba[end:-1:1]; init=UInt64(0))
end

function check_grayness(gray_codes::Vector{Vector{Int8}})
    len = length(gray_codes)
    for i in 1:len
        @test diff_one(gray_codes[i], gray_codes[mod1(i + 1, len)])
    end
    @test length(unique(map(binary_array_to_value, gray_codes))) == len
end

@testset "N-th Gray code" begin
    seed!()
    N = 2^16
    for _ in 1:100
        n = rand(1:N)
        n_minus1 = mod1(n - 1, N)
        n_plus1 = mod1(n + 1, N)
        g = gray_nth(n)
        g_minus1 = gray_nth(n_minus1)
        g_plus1 = gray_nth(n_plus1)
        @test diff_one(g_minus1, g)
        @test diff_one(g, g_plus1)

        b = gray_to_binary(g)
        nb = binary_array_to_value(b) + 1
        @test n == nb
    end
end

@testset "Gray code of given length" begin
    for len in 2:2:64
        gray_codes = gray_codes_of_len(len)
        check_grayness(gray_codes)
    end
end

@testset "Gray code - Chinese ring puzzle" begin
    for n in 2:8
        gc_gen = GrayCodeIter(n)
        gray_codes = [digits(Int8, g, base=2, pad=n) for g in gc_gen]
        check_grayness(gray_codes)
    end
end
end  # module


# elastic-net regularization

"""
  ElasticNet(λ::Real=1.0, μ::Real=1.0)

Returns the function `g(x) = μ||x||_1 + (λ/2)||x||²`, for a real parameters `μ, λ ⩾ 0`.
"""

immutable ElasticNet{R <: Real} <: ProximableFunction
  mu::R
  lambda::R
  function ElasticNet(mu::R, lambda::R)
    if lambda < 0 || mu < 0
      error("parameters μ, λ must be nonnegative")
    else
      new(mu, lambda)
    end
  end
end

ElasticNet{R <: Real}(mu::R=1.0, lambda::R=1.0) = ElasticNet{R}(mu, lambda)

function (f::ElasticNet){T <: RealOrComplex}(x::AbstractArray{T})
  return f.mu*vecnorm(x,1) + (f.lambda/2)*vecnorm(x,2)^2
end

function prox!{T <: Real}(f::ElasticNet, x::AbstractArray{T}, y::AbstractArray{T}, gamma::Real=1.0)
  sqnorm2x = zero(Float64)
  norm1x = zero(Float64)
  gm = gamma*f.mu
  gl = gamma*f.lambda
  for i in eachindex(x)
    y[i] = (x[i] + (x[i] <= -gm ? gm : (x[i] >= gm ? -gm : -x[i])))/(1 + gl)
    sqnorm2x += abs2(y[i])
    norm1x += abs(y[i])
  end
  return f.mu*norm1x + (f.lambda/2)*sqnorm2x
end

function prox!{T <: Complex}(f::ElasticNet, x::AbstractArray{T}, y::AbstractArray{T}, gamma::Real=1.0)
  sqnorm2x = zero(Float64)
  norm1x = zero(Float64)
  gm = gamma*f.mu
  gl = gamma*f.lambda
  for i in eachindex(x)
    y[i] = sign(x[i])*max(0, abs(x[i]) - gm)/(1 + gl)
    sqnorm2x += abs2(y[i])
    norm1x += abs(y[i])
  end
  return f.mu*norm1x + (f.lambda/2)*sqnorm2x
end

fun_name(f::ElasticNet) = "elastic-net regularization"
fun_dom(f::ElasticNet) = "AbstractArray{Real}, AbstractArray{Complex}"
fun_expr(f::ElasticNet) = "x ↦ μ||x||_1 + (λ/2)||x||²"
fun_params(f::ElasticNet) = "μ = $(f.mu), λ = $(f.lambda)"

function prox_naive{T <: RealOrComplex}(f::ElasticNet, x::AbstractArray{T}, gamma::Real=1.0)
  uz = max.(0, abs.(x) - gamma*f.mu)/(1 + f.lambda*gamma);
  return sign.(x).*uz, f.mu*vecnorm(uz,1) + (f.lambda/2)*vecnorm(uz)^2
end


### A Pluto.jl notebook ###
# v0.16.1

using Markdown
using InteractiveUtils

# ╔═╡ e8595a60-222f-11ec-0595-c9717ac06507
begin
	using Plots,SymPy, LaTeXStrings, LinearAlgebra
	import PlotlyJS
	plotlyjs()
end

# ╔═╡ 431922d9-e97a-4300-a482-2d458b66c67a
md""" ### Ejercicio 1
Considere la cónica dada por $y = x^2 − 4x + 5$ y la recta $L$ que pasa por $(2, 7)$ con
direcci´on $v = (1, 1)$
"""

# ╔═╡ 85cf0b95-4446-4e84-a6c3-f9d3fcf4cd61
md"""
1. En un mismo plano cartesiano grafique la recta y la c´onica, obtenga anal´ıticamente los
puntos de intersecci´on entre ambas y m´arquelos en su gr´afico.

2. Halle el ´area del tri´angulo definido por el v´ertice de la c´onica y los puntos de intersecci´on
obtenidos anteriormente.
"""

# ╔═╡ 53b8d020-b4a9-4c74-b0cc-dba03b6edbd3
# Definimos las variables s'imbolicas
@syms x λ

# ╔═╡ 4257606e-3eff-4124-aad3-517998f97d24
md"""
Definamos la conica
"""

# ╔═╡ 61b1bf99-507b-4379-b537-86ce040f1418
y = x^2 - 4x + 5

# ╔═╡ d17a8914-6ecf-4606-a664-7242d0f8f06c
md"""
Para la  recta tenemos la siguiente representaci'o

$$L  = \lambda (1, 1) + (2, 7)$$

pero para encontrar la interseccion con la par'abola va a ser m'as 'util representarlo en la forma can'onica de $y = m * x + b$

$$(x,y) = ( \lambda + 2, \lambda + 7 )$$

Igualando cada una de las componentes tenemos que

$$y = \lambda + 7 = (x-2) + 7 = x + 5$$
"""

# ╔═╡ 2056778d-12f0-4325-920f-f6c7e453918b
L =	x + 5

# ╔═╡ 4f6feaf8-5322-4afc-b31d-211761e222c2
md"""
Graficando ambas
"""

# ╔═╡ f676a35a-c61e-4547-b176-211dd3dc647b
begin
	p = plot()
	plot!(y,label=sympy.latex(y),xlims=(-2,6))
	plot!(L, label=sympy.latex(L))
end

# ╔═╡ d8e3eda0-cada-4047-81cc-137a54e1b5e6
md"""
Calculamos la intersecci'on entre la recta y la para'bola

`solve` busca las soluciones del sistema $S = 0$ entonces planteamos la igualdad como
$S = L - y = 0$ que es equivalente a tener $L=y$
"""

# ╔═╡ 897cfd67-1be7-40e4-87d9-c11bc9de55d4
interseccion = solve(y - L)

# ╔═╡ 67e7f9f5-6e78-4579-97f7-7c0349b39afd
y_interseccion = y.(interseccion)

# ╔═╡ 4d6550b8-4e9d-4437-84bd-d978e33bfdb8
md"""
Agregamos los puntos de la intersecci'on al gr'afico
"""

# ╔═╡ 997c5ff7-ac5d-484f-bcdf-a89194d112ee
p2 = scatter!(interseccion,y_interseccion,color=:black,label="interseccion",ax=p)

# ╔═╡ 19f1f8b8-0f5c-4388-b550-f4cdd7619311
md"""
Calculamos el vertice usando la formula de $x_{vert} = \frac{-b}{2a}$
y en nuestro caso queda

$$x_{vert} = \frac{-(-4)}{2*1} = 2$$
$$y_{vert} = y(x_{vert}) = 2^{2} - 4 * 2 + 5 = 4 - 8 + 5 = 1$$
"""

# ╔═╡ 8e1588d8-1d7a-4151-b8a1-afc3c1298887
p3 = scatter!([2],[1],color=:green,label="vertice",ax=p2)

# ╔═╡ 09baa7ce-fc86-42a5-8130-3c8125c93f5b
md"""
Entonces ya tenemos los tres vertices del triangulo
"""

# ╔═╡ 653aa355-0c9d-4520-befd-d3f91678ffaa
begin
	# defino con decimales por una cuestion del programa
	v₁ = [0.0, 5.0]
	v₂ = [5.0, 10.0]
	v₃ = [2.0, 1.0]
	nothing
end

# ╔═╡ 1938fc99-5366-4bc0-a2b3-892d7281db93
md"""
Ahora para hallar el area vamos a utilizar el determinante entre dos vectores que definan el triangulo. Voy a considerar los vectores que van desde el vertice $v_{3}$ a los dos puntos de las intersecciones, abusando un poco la notacion $V_{1,3} = v_{1} - v_{3}$, $V_{1,3} = v_{2} - v_{3}$
"""

# ╔═╡ 0f723758-c34e-4a3b-ad72-853cc23b29fc
m = [v₁-v₃ v₂-v₃]

# ╔═╡ 253ae086-b3b0-4243-b05d-4e575166aa53
det(m)

# ╔═╡ 9003d85b-eaf0-44f9-b2b7-1dd990e4fd76
md"""
El determinante es negativo porque estamos tomando como primer vector el que est'a m'as a la izquierda. Si invertimos el orden en el que armamos la matriz, el determinante va a dar positivo, estamos alternando dos columnas :)

En conclusion el a'rea es el valor absoluto del determinante dividido dos, entonces tenemos que

``area =`` $(abs(det(m))/2)
"""

# ╔═╡ c18c2f4b-1e5f-463f-8464-0a6387896efc
md"""
## Ejercicio 2.

Sean $\pi : x + 2y + 2z = 12$ y $P = (1, 0, 1)$.

a) Hallar el punto de π que se encuentra a menor distancia del punto P y calcular la distancia
de $P$ al plano $\pi$.

b) Hallar el volumen del tetraedro (pir´amide de base triangular) definido por P y las intersecciones del plano π con los ejes coordenados. (Recuerde que el volumen del tetraedo es un
sexto del volumen del paralelep´ıdedo)
"""

# ╔═╡ 0f3486cc-8de9-452c-a0a1-b8c5277c1592
n = [1, 2, 2]

# ╔═╡ f4ee2c3e-7a1b-4d4a-99cf-0dda3ae572d7
P = [1,0,1]

# ╔═╡ cf0c4904-6b99-4af7-8aee-d03593bc2091
L₂ = λ*n + P

# ╔═╡ e86f3da1-ab64-4582-9fc7-8f12966c318f
π(v) = n ⋅ v - 12

# ╔═╡ 84f78af9-2866-404e-a121-3e3c6afe617b
# SymMatrix esta indexada desde 0 :(
π(L₂)

# ╔═╡ 9bf041fa-c284-4425-831c-2d8a207e54e2
λₛₒₗ = solve(π(L₂))[1]

# ╔═╡ 512fadab-9352-4d45-b73e-d754b30114e4
Q = subs.(L₂,λ => λₛₒₗ)

# ╔═╡ 6612a222-06c1-47a8-b024-146ca8caea08
md"""
Un poco de sanity check, comprobamos que $Q \in \pi$
"""

# ╔═╡ 604e2572-57d6-4076-b4bc-35adcceb7994
π(Q)

# ╔═╡ ef868e86-0a6a-47fb-b2a5-d9190cd03c0a
md"""
Con esto ya podemos calcular la distancia entre $P$ y $Q$
"""

# ╔═╡ 74bf0f00-bc45-4d26-9c61-f164de3d21e0
md"""
``dist(P,Q) = \vert P- Q \vert =`` $(norm(P - Q))
"""

# ╔═╡ 50432a00-fdbe-448e-a6c1-89b1d01d435d
md"""
#### b) Buscamos la interseccion de $\pi$ con los ejes coordenados
"""

# ╔═╡ 4bf801a5-b443-46d1-a110-ab8096527116
md"""
Primero definimos el vector can'onico en una direccio'on
"""

# ╔═╡ 2136e05b-bef2-4dc8-8723-3fbb8360cba0
e₁ = [1,0,0]

# ╔═╡ 5532b807-94e2-4ff2-9b65-41d1423863c6
md"""
Como queremos encontrar la intersecci'on entre el eje y el plano, definimos la recta que sigue al eje coordenado como
"""

# ╔═╡ 904d25d1-2244-4f76-ac1c-b1fef76ff41a
λ * e₁

# ╔═╡ 2ba19d1c-f22e-47c8-b81c-979e0edd7348
md"""
Cuando lo evaluamos en la definici'on del plano tenemos que la interseccio'n occurre cuando la siguiente es igual a $0$
"""

# ╔═╡ 9eeb302c-a277-437d-9e95-345b72d1a3a4
π(λ * e₁)

# ╔═╡ 15949e72-93cf-4aa6-8524-5b55fe9eb229
md"""
Y eso ocurre cuando ``\lambda =`` $(solve(π(λ * e₁)))
"""

# ╔═╡ 6935e6f6-e926-4766-89a4-8d86408cc15d
interseccion_con_π(v) = solve(π(λ * v))[1]

# ╔═╡ aed97c10-bcae-4552-b522-afb0a6073c7a
md"""
Extendemos el c'alculo de la intersecci'on del plano con los otros dos ejes obteniendo los siguentes puntos
"""

# ╔═╡ 760596e6-3937-4024-b3b4-7bfae97c4a4f
begin
	e₂ = [0,1,0]
	e₃ = [0,0,1]
	x₁ = interseccion_con_π(e₁) * e₁
	x₂ = interseccion_con_π(e₂) * e₂
	x₃ = interseccion_con_π(e₃) * e₃
	x₁, x₂, x₃
end

# ╔═╡ 64d47104-23e7-492c-aa5e-c6eee7f6d10d
md"""
Para tener un poco m'as de intuici'on los graficamos
"""

# ╔═╡ ff31fe54-2f96-4e12-bf62-395dd29fa515
begin
	figura = scatter3d([P[1]],[P[2]],[P[3]],label="P",xlabel="x",ylabel="y",zlabel="z")
	for p in [x₁, x₂, x₃]
		scatter3d!([p[1]],[p[2]],[p[3]],label=false,ax=figura)
	end
	figura
end

# ╔═╡ 6867d0da-516e-4924-b3f3-be7bbe75d4fc
md"""
Para calcular el volumen primero consideramos los vectores que van de $P$ a cada uno de los tres puntos $V_{i}$ que encontramos antes. Para eso calculamos $V_{i} - P$, para cada uno de los ejes y los ordenamos a cada uno como una columna de una matriz de manera de que podamos calcular el determinante
"""

# ╔═╡ 9ca33e7d-aa40-4970-9072-bcf0f754ec04
M = [x₁ x₂ x₃] .- P

# ╔═╡ fe385398-3bd1-4662-8411-e2c9beda9a9f
md"""
Que tiene el determinante igual a
"""

# ╔═╡ 672d62df-7c33-4260-8c4f-a72e8a900bd3
det(M)

# ╔═╡ c389944d-1d91-44aa-a28d-d0848bb10228
md"""
Usando la ayuda del enunciado tenemos que el volumen del tetaedro es ``\frac{\vert det(M)\vert}{6} = `` $(det(M)/6)
"""

# ╔═╡ e7d5a0e0-0b6b-4012-88cd-7e50283fb721
md"""
### Ejercicio 3.

Para $\alpha \in \mathbb{R}$ considere la matriz $A \in \mathbb{R}^{3×3}$ dada por

$\left[
\begin{array}{rrr}
 1       & 0          & \alpha     \\
 \alpha  & \alpha - 1 & \alpha^{2} \\
 0       & 1          & \alpha - 2
\end{array}\right]$

1. Halle todos los valores de $\alpha$ para los cuales $A^{2021} − A^{2022}$ no resulte inversible.

2. Ponga $\alpha = 2$. Utilice el m´etodo de Gauss para resolver

$$Ax = e_{1} + e_{2} − e_{3}$$

`INDICANDO TODAS LAS OPERACIONES DE FILAS QUE UTILIZA. Exhiba la solucien forma param´etrica y la matriz escalonada reducida del sistema; se˜nale el rango de
A.`
"""

# ╔═╡ fc2349c9-fb1f-4ce3-94fc-adb98f3170b8
# Definimos el simbolo
@syms α

# ╔═╡ 30e16586-b504-4332-9f6c-cdeb3f9c686c
A = [1 0 α;
	α α-1 α^2;
	0 1 α-2]

# ╔═╡ 2f8356bc-311a-4826-861e-4852ed01bca1
md"""
El ejercicio nos pide que calculemos cuando la siguiente matriz no es inversible $A^{2021} − A^{2022}$, lo cual parece una locura. Pero recordemos que una manera de evaluar si una matriz es inversible es a partir del determinante. Y la matriz va a ser inversible en el caso de que su determinante sea distinto de 0
"""

# ╔═╡ 45d7938f-a9ff-4a21-b0f8-74a7b69e1a3d
md"""
$\begin{align}
det(A^{2021} − A^{2022}) &= det( A^{2021}*(I-A)  ) \\
                         &= det( A^{2021} ) * det(I-A)\\
                         &= det( A )^{2021} * det(I-A)
\end{align}$
"""

# ╔═╡ af547106-640f-4d89-b96d-b1d625822697
I - A

# ╔═╡ a2779834-7808-4bad-a97a-bc90dba2adc7
determinante = det(A)^2021 * det(I-A)

# ╔═╡ d9ef00bd-1ac5-4406-9cb7-ae9d90d2387e
md"""
El determinante se anula en el caso de que cualquiera de los terminos sea igual a cero, entonces tenemos que
"""

# ╔═╡ 76c7aed0-4bac-4a03-8a07-00583c571c52
solve(det(A))

# ╔═╡ 180d6fe0-baeb-4c05-bfc9-213a6f1ec07c
solve(det(I-A))

# ╔═╡ a7da009c-b867-46d2-84a2-087287521aa8
md"""
Entonces es la matriz no es inversible si $\alpha \in \{0,1,2\}$
"""

# ╔═╡ 5522536b-a0df-41f8-8525-856923f49104
md"""
Para resolver el punto b), reemplazamos $\alpha = 2$. Notemos que es uno de los valores en los que el la matriz no era inversible, eso nos esta diciendo que el sistema no est'a completamete determinado.
"""

# ╔═╡ 337404a1-514b-4f40-9aa7-738d0c07d34f
Aₛ = subs.(A, α=>2)

# ╔═╡ 7dcb7519-f6cc-47b6-bbf2-1896a0053a85
md"""
Resolviendo el sistema por el metodo de Gauss-Jordan

$$A x = (1,1,-1)$$
"""

# ╔═╡ dd6b45de-fa40-4697-a372-d7f6a75bc704
md"""
Llegamos a que la solucion es el siguiente vector
"""

# ╔═╡ e052a4ad-90a0-4f7f-a1e7-a35b92270d74
Aₛ\[1,1,-1]

# ╔═╡ 65dcc377-8278-4c08-867b-012065989b1f
md"""
Que representa la recta

``
L_{s} = λ (-2,0,1) + (1,-1,0)
``
"""

# ╔═╡ c2c157cb-29fa-488b-a5dd-caef9e392c6b
md"""
### Ejercicio 4.

a) Sean $u, v \in \mathbb{R}^{2}$ dos vectores tales que $det(u, v) = 3$.
Hallar el ´area del paralelogramo determinado por los vectores $2u + 3v$ y $u − 4v$.

b) Decidir si la siguiente afirmaci´on es verdadera o falsa. Si es verdadera, dar una demostraci´on. Si es falsa, dar un contraejemplo.

Sean $L_{1}$ y $L_{2}$ son dos rectas en $R^{3}$

Si $L_{1} \cap L_{2} = \emptyset$, entonces $L_{1}$ y $L_{2}$ son paralelas.
"""

# ╔═╡ 1dd55ddd-2c09-4d8c-83d3-442ebcf0d579
# definimos los vectores simbolicos
begin
	@syms u[1:2] v[1:2]
end

# ╔═╡ 0bd81932-75a6-4b74-a264-bb16ae798a44
det([u v])

# ╔═╡ c3ca6592-a758-40fc-96c5-e8609071697f
det([2u+3v u-4v])

# ╔═╡ 279a2774-a565-4ffa-9577-b2e987abed37
simplify(det([2u+3v u-4v]) / det([u v]))

# ╔═╡ 1dd28947-9fa2-42bc-9666-6e1b5e12a147
md"""
En el punto **b)** La afirmación es **falsa**, pues pueden existir dos rectas que no sean paralelas y no tengan intersección

Por ejemplo, si tomamos:

$$L_{a} = \lambda_{a} (1,0,0) + (0,0,0)$$

$$L_{b} = \lambda_{b} (0,1,0) + (0,0,1)$$
"""

# ╔═╡ 2b0dc6fe-ae32-48c9-a400-ad5fb8fbef4e
Lₐ(λ) = λ*[1,0,0]

# ╔═╡ 40420c6d-122b-454d-9954-8ec29765f3f2
Lₚ(λ) = λ*[0,1,0] + [0,0,1]

# ╔═╡ be180c4f-177b-41a7-83d3-5a0220c9ad0e
begin
t = -1:1
# scatter3d(,)
end

# ╔═╡ 067ffcf8-a398-4e50-bcf7-5425906f4a87
collect(map(Array,zip(Lₐ.(t)...)))

# ╔═╡ a1ce3aac-6e19-4de0-bcd5-4e86b26aab71
let
x,y,z =	collect(zip(Lₐ.(t)...))
# plot3d([x],[y],[z],xlabel="x",ylabel="y",zlabel="z")
end

# ╔═╡ 3cf6ffc2-0f08-41f7-adaa-9fa22f585881
# Para referencia
repr("text/latex",A);

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6"

[compat]
LaTeXStrings = "~1.2.1"
PlotlyJS = "~0.18.7"
Plots = "~1.22.3"
SymPy = "~1.0.52"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[AssetRegistry]]
deps = ["Distributed", "JSON", "Pidfile", "SHA", "Test"]
git-tree-sha1 = "b25e88db7944f98789130d7b503276bc34bc098e"
uuid = "bf4720bc-e11a-5d0c-854e-bdca1663c893"
version = "0.1.0"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[BinDeps]]
deps = ["Libdl", "Pkg", "SHA", "URIParser", "Unicode"]
git-tree-sha1 = "1289b57e8cf019aede076edab0587eb9644175bd"
uuid = "9e28174c-4ba2-5203-b857-d8d62c4213ee"
version = "1.0.2"

[[Blink]]
deps = ["Base64", "BinDeps", "Distributed", "JSExpr", "JSON", "Lazy", "Logging", "MacroTools", "Mustache", "Mux", "Reexport", "Sockets", "WebIO", "WebSockets"]
git-tree-sha1 = "08d0b679fd7caa49e2bca9214b131289e19808c0"
uuid = "ad839575-38b3-5650-b840-f874b8c74a25"
version = "0.12.5"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "e8a30e8019a512e4b6c56ccebc065026624660e8"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.7.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.15.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[CommonEq]]
git-tree-sha1 = "d1beba82ceee6dc0fce8cb6b80bf600bbde66381"
uuid = "3709ef60-1bee-4518-9f2f-acd86f176c50"
version = "0.2.0"

[[CommonSolve]]
git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f"
uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
version = "0.2.0"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "31d0151f5716b655421d9d75b7fa74cc4e744df2"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.39.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[Conda]]
deps = ["JSON", "VersionParsing"]
git-tree-sha1 = "299304989a5e6473d985212c28928899c74e9421"
uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d"
version = "1.5.2"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[FunctionalCollections]]
deps = ["Test"]
git-tree-sha1 = "04cb9cfaa6ba5311973994fe3496ddec19b6292a"
uuid = "de31a74c-ac4f-5751-b3fd-e18cd04993ca"
version = "0.5.0"

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+0"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "c2178cfbc0a5a552e16d097fae508f2024de61a3"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.59.0"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "ef49a187604f865f4708c90e3f431890724e9012"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.59.0+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "14eece7a3308b4d8be910e265c724a6ba51a9798"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.16"

[[HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+0"

[[Hiccup]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "6187bb2d5fcbb2007c39e7ac53308b0d371124bd"
uuid = "9fb69e20-1954-56bb-a84f-559cc56a8ff7"
version = "0.2.2"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSExpr]]
deps = ["JSON", "MacroTools", "Observables", "WebIO"]
git-tree-sha1 = "bd6c034156b1e7295450a219c4340e32e50b08b1"
uuid = "97c1335a-c9c5-57fe-bc5d-ec35cebe8660"
version = "0.5.3"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[Kaleido_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "2ef87eeaa28713cb010f9fb0be288b6c1a4ecd53"
uuid = "f7e6163d-2fa5-5f23-b69c-1db539e41963"
version = "0.1.0+0"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.6"

[[Lazy]]
deps = ["MacroTools"]
git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f"
uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"
version = "0.15.1"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "34dc30f868e368f8a17b728a1238f3fcda43931a"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.3"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "5a5bc6bf062f0f95e62d0fe0a2d99699fed82dd9"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.8"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[Mustache]]
deps = ["Printf", "Tables"]
git-tree-sha1 = "36995ef0d532fe08119d70b2365b7b03d4e00f48"
uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
version = "1.0.10"

[[Mux]]
deps = ["AssetRegistry", "Base64", "HTTP", "Hiccup", "Pkg", "Sockets", "WebSockets"]
git-tree-sha1 = "82dfb2cead9895e10ee1b0ca37a01088456c4364"
uuid = "a975b10e-0019-58db-a62f-e48ff68538c9"
version = "0.7.6"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Observables]]
git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
version = "0.4.0"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "9d8c00ef7a8d110787ff6f170579846f776133a9"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.4"

[[Pidfile]]
deps = ["FileWatching", "Test"]
git-tree-sha1 = "1be8660b2064893cd2dae4bd004b589278e4440d"
uuid = "fa939f87-e72e-5be4-a000-7fc836dbe307"
version = "1.2.0"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "2537ed3c0ed5e03896927187f5f2ee6a4ab342db"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.14"

[[PlotlyBase]]
deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"]
git-tree-sha1 = "180d744848ba316a3d0fdf4dbd34b77c7242963a"
uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
version = "0.8.18"

[[PlotlyJS]]
deps = ["Base64", "Blink", "DelimitedFiles", "JSExpr", "JSON", "Kaleido_jll", "Markdown", "Pkg", "PlotlyBase", "REPL", "Reexport", "Requires", "WebIO"]
git-tree-sha1 = "ec6bc7270269be2d565b272116ca74ca2f8bd9ab"
uuid = "f0f68f2c-4968-5e81-91da-67840de0976a"
version = "0.18.7"

[[Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"]
git-tree-sha1 = "cfbd033def161db9494f86c5d18fbf874e09e514"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.22.3"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[PyCall]]
deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"]
git-tree-sha1 = "169bb8ea6b1b143c5cf57df6d34d022a7b60c6db"
uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
version = "1.92.3"

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[RecipesBase]]
git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.1"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "793793f1df98e3d7d554b65a107e9c9a6399a6ed"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.7.0"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "8cbbc098554648c84f79a463c9ff0fd277144b6c"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.10"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.3"

[[SymPy]]
deps = ["CommonEq", "CommonSolve", "LinearAlgebra", "Markdown", "PyCall", "RecipesBase", "SpecialFunctions"]
git-tree-sha1 = "1ef257ecbcab8058595a68ca36a6844b41babcbd"
uuid = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6"
version = "1.0.52"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "1162ce4a6c4b7e31e0e6b14486a6986951c73be9"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.5.2"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[URIParser]]
deps = ["Unicode"]
git-tree-sha1 = "53a9f49546b8d2dd2e688d216421d050c9a31d0d"
uuid = "30578b45-9adc-5946-b283-645ec420af67"
version = "0.4.1"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[VersionParsing]]
git-tree-sha1 = "80229be1f670524750d905f8fc8148e5a8c4537f"
uuid = "81def892-9a0e-5fdd-b105-ffc91e053289"
version = "1.2.0"

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

[[WebIO]]
deps = ["AssetRegistry", "Base64", "Distributed", "FunctionalCollections", "JSON", "Logging", "Observables", "Pkg", "Random", "Requires", "Sockets", "UUIDs", "WebSockets", "Widgets"]
git-tree-sha1 = "5fe32e4086d49f7ab9b087296742859f3ae6d62a"
uuid = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29"
version = "0.8.16"

[[WebSockets]]
deps = ["Base64", "Dates", "HTTP", "Logging", "Sockets"]
git-tree-sha1 = "f91a602e25fe6b89afc93cf02a4ae18ee9384ce3"
uuid = "104b5d7c-a370-577a-8038-80a2059c5097"
version = "1.5.9"

[[Widgets]]
deps = ["Colors", "Dates", "Observables", "OrderedCollections"]
git-tree-sha1 = "80661f59d28714632132c73779f8becc19a113f2"
uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62"
version = "0.6.4"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╠═e8595a60-222f-11ec-0595-c9717ac06507
# ╟─431922d9-e97a-4300-a482-2d458b66c67a
# ╟─85cf0b95-4446-4e84-a6c3-f9d3fcf4cd61
# ╟─53b8d020-b4a9-4c74-b0cc-dba03b6edbd3
# ╟─4257606e-3eff-4124-aad3-517998f97d24
# ╠═61b1bf99-507b-4379-b537-86ce040f1418
# ╟─d17a8914-6ecf-4606-a664-7242d0f8f06c
# ╠═2056778d-12f0-4325-920f-f6c7e453918b
# ╟─4f6feaf8-5322-4afc-b31d-211761e222c2
# ╟─f676a35a-c61e-4547-b176-211dd3dc647b
# ╟─d8e3eda0-cada-4047-81cc-137a54e1b5e6
# ╟─897cfd67-1be7-40e4-87d9-c11bc9de55d4
# ╟─67e7f9f5-6e78-4579-97f7-7c0349b39afd
# ╟─4d6550b8-4e9d-4437-84bd-d978e33bfdb8
# ╠═997c5ff7-ac5d-484f-bcdf-a89194d112ee
# ╟─19f1f8b8-0f5c-4388-b550-f4cdd7619311
# ╠═8e1588d8-1d7a-4151-b8a1-afc3c1298887
# ╟─09baa7ce-fc86-42a5-8130-3c8125c93f5b
# ╠═653aa355-0c9d-4520-befd-d3f91678ffaa
# ╟─1938fc99-5366-4bc0-a2b3-892d7281db93
# ╠═0f723758-c34e-4a3b-ad72-853cc23b29fc
# ╠═253ae086-b3b0-4243-b05d-4e575166aa53
# ╟─9003d85b-eaf0-44f9-b2b7-1dd990e4fd76
# ╟─c18c2f4b-1e5f-463f-8464-0a6387896efc
# ╠═0f3486cc-8de9-452c-a0a1-b8c5277c1592
# ╠═f4ee2c3e-7a1b-4d4a-99cf-0dda3ae572d7
# ╠═cf0c4904-6b99-4af7-8aee-d03593bc2091
# ╠═e86f3da1-ab64-4582-9fc7-8f12966c318f
# ╟─84f78af9-2866-404e-a121-3e3c6afe617b
# ╠═9bf041fa-c284-4425-831c-2d8a207e54e2
# ╠═512fadab-9352-4d45-b73e-d754b30114e4
# ╟─6612a222-06c1-47a8-b024-146ca8caea08
# ╠═604e2572-57d6-4076-b4bc-35adcceb7994
# ╟─ef868e86-0a6a-47fb-b2a5-d9190cd03c0a
# ╟─74bf0f00-bc45-4d26-9c61-f164de3d21e0
# ╟─50432a00-fdbe-448e-a6c1-89b1d01d435d
# ╟─4bf801a5-b443-46d1-a110-ab8096527116
# ╠═2136e05b-bef2-4dc8-8723-3fbb8360cba0
# ╟─5532b807-94e2-4ff2-9b65-41d1423863c6
# ╠═904d25d1-2244-4f76-ac1c-b1fef76ff41a
# ╟─2ba19d1c-f22e-47c8-b81c-979e0edd7348
# ╠═9eeb302c-a277-437d-9e95-345b72d1a3a4
# ╟─15949e72-93cf-4aa6-8524-5b55fe9eb229
# ╟─6935e6f6-e926-4766-89a4-8d86408cc15d
# ╟─aed97c10-bcae-4552-b522-afb0a6073c7a
# ╟─760596e6-3937-4024-b3b4-7bfae97c4a4f
# ╟─64d47104-23e7-492c-aa5e-c6eee7f6d10d
# ╟─ff31fe54-2f96-4e12-bf62-395dd29fa515
# ╟─6867d0da-516e-4924-b3f3-be7bbe75d4fc
# ╟─9ca33e7d-aa40-4970-9072-bcf0f754ec04
# ╟─fe385398-3bd1-4662-8411-e2c9beda9a9f
# ╟─672d62df-7c33-4260-8c4f-a72e8a900bd3
# ╟─c389944d-1d91-44aa-a28d-d0848bb10228
# ╟─e7d5a0e0-0b6b-4012-88cd-7e50283fb721
# ╟─fc2349c9-fb1f-4ce3-94fc-adb98f3170b8
# ╠═30e16586-b504-4332-9f6c-cdeb3f9c686c
# ╟─2f8356bc-311a-4826-861e-4852ed01bca1
# ╟─45d7938f-a9ff-4a21-b0f8-74a7b69e1a3d
# ╠═af547106-640f-4d89-b96d-b1d625822697
# ╠═a2779834-7808-4bad-a97a-bc90dba2adc7
# ╟─d9ef00bd-1ac5-4406-9cb7-ae9d90d2387e
# ╠═76c7aed0-4bac-4a03-8a07-00583c571c52
# ╠═180d6fe0-baeb-4c05-bfc9-213a6f1ec07c
# ╟─a7da009c-b867-46d2-84a2-087287521aa8
# ╟─5522536b-a0df-41f8-8525-856923f49104
# ╠═337404a1-514b-4f40-9aa7-738d0c07d34f
# ╟─7dcb7519-f6cc-47b6-bbf2-1896a0053a85
# ╟─dd6b45de-fa40-4697-a372-d7f6a75bc704
# ╟─e052a4ad-90a0-4f7f-a1e7-a35b92270d74
# ╟─65dcc377-8278-4c08-867b-012065989b1f
# ╟─c2c157cb-29fa-488b-a5dd-caef9e392c6b
# ╟─1dd55ddd-2c09-4d8c-83d3-442ebcf0d579
# ╠═0bd81932-75a6-4b74-a264-bb16ae798a44
# ╠═c3ca6592-a758-40fc-96c5-e8609071697f
# ╠═279a2774-a565-4ffa-9577-b2e987abed37
# ╟─1dd28947-9fa2-42bc-9666-6e1b5e12a147
# ╠═2b0dc6fe-ae32-48c9-a400-ad5fb8fbef4e
# ╠═40420c6d-122b-454d-9954-8ec29765f3f2
# ╠═be180c4f-177b-41a7-83d3-5a0220c9ad0e
# ╠═067ffcf8-a398-4e50-bcf7-5425906f4a87
# ╠═a1ce3aac-6e19-4de0-bcd5-4e86b26aab71
# ╟─3cf6ffc2-0f08-41f7-adaa-9fa22f585881
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


# Seasonality and unobserved components
# models: an overview
# Andrew Harvey
# December 4, 2006

# Are Seasonal Patterns Constant Over Time?
# A Test for Seasonal Stability
# Fabio CANOVA
# Bruce E. HANSEN
# Journal of Business & Economic Statistics, July 1995, Vol. 13, No. 3

λ(j::Int, s::Int) = (2*pi*j)/s

const CRIT_VALS_05 = [0.470, 0.749, 1.01, 1.24, 1.47, 1.68, 1.9, 2.11, 2.32, 2.54, 2.75, 2.96]

function crit_val_05_generalized_von_mises_distribution(s::Int)
    return s > 12 ? 0.269 * s^0.928 : CRIT_VALS_05[s]
end

function π_statistic(ε::Vector{Fl}, σ::Fl, T::Int) where Fl
    return (T^(-2)*σ^(-2))*
            sum(
                sum(ε[i]*(-1)^(i) for i = 1:t) for t = 1:T
            )
end

function std_statistic(ε::Vector{Fl}, σ::Fl, T::Int, s::Int, j::Int) where Fl
    return (2*T^(-2)*σ^(-2))*
            sum(
                sum(ε[i]*cos(λ(j, s)*i) for i = 1:t)^2
                +
                sum(ε[i]*sin(λ(j, s)*i) for i = 1:t)^2 for t = 1:T
            )
end

function test_statistic(ε::Vector{Fl}, σ::Fl, T::Int, s::Int) where Fl
    # joint statistical test for all frequencies in
    # trigonometric pattern
    ω = 0
    # for each frequency in the trigonometric pattern
    for j = 1:floor(Int, s/2)
        ω += j == s/2 ? π_statistic(ε, σ, T) : std_statistic(ε, σ, T, s, j)
    end
    return ω
end

function build_std(T::Int, s::Int, j::Int)
    # add cossine and sine with frequency (2*pi*j)/s
    # to exogenous matrix X
    return hcat(cos.(λ(j, s)*(1:T)), sin.(λ(j, s)*(1:T)))
end

function build_π(T::Int, s::Int, j::Int)
    # when j = s/2
    # add cossine with frequency pi and intercept
    # to exogenous matrix X
    return hcat(cos.(λ(j, s)*(1:T)), ones(T))
end

function build_X(s::Int, T::Int, Fl::Type)
    # create the exogenous matrix
    X = Array{Fl, 2}(undef, T, s)
    # for each frequency in the trigonometric pattern
    for j = 1:floor(Int, s/2)
        X[:,[2*j-1, 2*j]] = j == s/2 ? build_π(T, s, j) : build_std(T, s, j)
    end
    return X
end

function seasonal_regression(y::Vector{Fl}, s::Int, T::Int) where Fl
    X = build_X(s, T, Fl)
    return y - X * (X \ y)
end

function seasonal_stationarity_test(y::Vector{Fl}, s::Int) where Fl
    T  = length(y)
    ε  = seasonal_regression(y, s, T)
    σ  = std(ε)
    ω  = test_statistic(ε, σ, T, s)
    crit_val = crit_val_05_generalized_von_mises_distribution(s)
    res = ω - crit_val
    res > 0 ? println("Rejected seasonal stationarity at 5% significance level"*
            " Test Statistic: $ω - Critical Value: $crit_val") :
              println("Didn't reject seasonal stationarity at 5% significance level"*
            " Test Statistic: $ω - Critical Value: $crit_val")
    return res > 0 ? false : true
end


using LinearAlgebra

function decomp_qr(A)

    (m,n) = size(A);
    R = zeros(n,n);
    Q = zeros(m,n);

    for j = 1:n

        soma = zeros(m,1);

        for i = 1 : j-1
            R[i,j] = Q[:,i]' * A[:,j];
            soma = soma + R[i,j]*Q[:,i];
        end

        v = A[:,j] - soma;
        R[j,j] = norm(v);
        Q[:,j] = v/R[j,j];

    end

    return (Q,R);

end


using Random, Distributions, Plots; pyplot()
Random.seed!(0)

lambda  = 1/4.5
expDist = Exponential(1/lambda)
n, N    = 10, 10^6

means     = Array{Float64}(undef, N)
variances = Array{Float64}(undef, N)

for i in 1:N
    data = rand(expDist,n)
    means[i] = mean(data)
    variances[i] = var(data)
end

println("Actual mean: ",mean(expDist),
		"\nMean of sample means: ",mean(means))
println("Actual variance: ",var(expDist),
	"\nMean of sample variances: ",mean(variances))

stephist(means, bins=200, c=:blue, normed=true,
	label="Histogram of Sample Means")
stephist!(variances, bins=600, c=:red, normed=true,
	label="Histogram of Sample Variances", xlims=(0,40), ylims=(0,0.4),
    	xlabel = "Statistic value", ylabel = "Density")


using RunTests
using Base.Test

@testmodule HouseHoldersTest begin
  using MLLibrary
  function test_QRDecompose()
    A=[2. 2 4. 18.;
       1. 3. -2. 1.;
       3. 1. 3. 14.]

    Q,R = MLLibrary.LinearAlgebra.HouseHolders.QRDecompose(A)
    @test round(Q,2) ==[-.53 -.22 .82;-.27 -.87 -.41; -.8 .44 -.41]
    @test round(R,2)==[-3.74 -2.67 -4.01 -21.11;0 -2.62 2.18 1.31; 0 0 2.86 8.57]
    @test round(norm(Q)) ==1.

    B=[1. -1. -1.;
       1. 2. 3.;
       2. 1. 1.;
       2. -2. 1.;
       3. 2. 1.]
     Q,R = MLLibrary.LinearAlgebra.HouseHolders.QRDecompose(B)
     @test round(Q,2) ==[-.23 -.23 -.46 -.46 -.69;.35 -.49 -.13 .71 -.34;-.37 .7 -.06 .47 -.38; -.67 -.42 .59 .11 -.1; -.49 -.19 -.65 .23 .5]'
     @test round(R,2) ==[-4.36 -1.15 -2.06; 0 -3.56 -1.58; 0 0 2.5; 0 0 0; 0 0 0]
     @test round(norm(Q)) ==1.  end

  function test_decompose()
    A=[2. 2 4. 18.;
       1. 3. -2. 1.;
       3. 1. 3. 14.]

    Q,R = MLLibrary.LinearAlgebra.HouseHolders.decompose(A)
    @test round(Q,2) ==[-.53 -.22 .82;-.27 -.87 -.41; -.8 .44 -.41]'
    @test round(R,2)==[-3.74 -2.67 -4.01 -21.11;0 -2.62 2.18 1.31; 0 0 2.86 8.57]
    @test round(norm(Q)) ==1.

    B=[1. -1. -1.;
       1. 2. 3.;
       2. 1. 1.;
       2. -2. 1.;
       3. 2. 1.]
     Q,R = MLLibrary.LinearAlgebra.HouseHolders.decompose(B)
     @test round(Q,2) ==[-.23 -.23 -.46 -.46 -.69;.35 -.49 -.13 .71 -.34;-.37 .7 -.06 .47 -.38; -.67 -.42 .59 .11 -.1; -.49 -.19 -.65 .23 .5]
     @test round(R,2) ==[-4.36 -1.15 -2.06; 0 -3.56 -1.58; 0 0 2.5; 0 0 0; 0 0 0]
     @test round(norm(Q)) ==1.

  end

end


# Algorithm 2.8
# Approximate the root of a function by constructing a parabola
# between three points and intersect it with y = 0 to find the
# next approximation.

function muller(f, x0, x1, x2, tol, n0)
	h1 = x1 - x0
	h2 = x2 - x1
	δ1 = (f(x1) - f(x0))/h1
	δ2 = (f(x2) - f(x1))/h2
	d = (δ2 - δ1)/(h2 + h1)
	for i ∈ 3:n0
		b = δ2 + h2 * d
		D = (b^2 -4f(x2)d)^(1/2)
		E = 0
		if abs(b - D) < abs(b + D)
			E = b + D
		else
			E = b - D
		end
		h = (-2f(x2))/E
		p = x2 + h
		if abs(h) < tol
			return p
		end
		x0 = x1
		x1 = x2
		x2 = p
		h1 = x1 - x0
		h2 = x2 - x1
		δ1 = (f(x1) - f(x0))/h1
		δ2 = (f(x2) - f(x1))/h2
		d = (δ2 - δ1)/(h2 + h1)
	end
	throw(ArgumentError("Method failed"))
end

println(muller(x -> (16x^4 - 40x^3 + 5x^2 + 20x +6), 0.5, 1.0, 1.5, 10^-5, 50))


# p21.jl - eigenvalues of Mathieu operator -u_xx + 2qcos(2x)u
#         (compare p8.jl and p. 724 of Abramowitz & Stegun)

N = 42; h = 2*pi/N; x = h*(1:N);
D2 = toeplitz([-pi^2/(3*h^2)-1/6; @. -.5*(-1)^(1:N-1)/sin(h*(1:N-1)/2)^2]);
qq = 0:.2:15; data = [];
for q = qq;
    e = sort(eigvals(-D2 + 2*q*diagm(cos.(2*x))));
    data = [data; e[1:11]'];
end
clf(); subplot(1,2,1);
plot(qq,data[:,1:2:end],"b-");
plot(qq,data[:,2:2:end],"b--");
xlabel("q"); ylabel("λ");
axis([0,15,-24,32]); yticks(-24:4:32);


using Distributions

lRange = 1; uRange = 9;         unidd    = DiscreteUniform(lRange,uRange)
p = 0.8;                         bernd    = Bernoulli(p)
n = 20; p = 0.8;                 bind     = Binomial(n,p)
ps = [0.2,0.5,0.2,0.1];          catd     = Categorical(ps)
n=20; ps = [0.2,0.5,0.3];        multind  = Multinomial(n, ps)
p = 0.2;                         geomd    = Geometric(p)
sAv = 10; fAv = 20; nTrials = 3; hypgeomd = Hypergeometric(sAv, fAv, nTrials)
# hypergeometrical multivariate form not available
rate = 10;                       poissd   = Poisson(rate)
nSucc =10; p = 0.2;              pascd    = NegativeBinomial(nSucc,p) # Return the number of failures before n successes instead of total trials to n successes

lRange = 1; uRange = 9;          unicd    = Uniform(lRange,uRange)
rate = 2.5;                      expd     = Exponential(rate)
μ = 2; σsq = 5 ;                 normd    = Normal(μ,sqrt(σsq))  # parametrised by sd!
n = 5; rate = 2.5;               erld     = Erlang(n,rate)
μ = 2.5; σ = 2.5;                cuachyd  = Cauchy(μ, σ)
df = 3;                          chisqd   = Chisq(df)
df = 4.5;                        td       = TDist(df)
df1 = 6 ; df2 = 7;               fd       = FDist(df1, df2)
shapeα = 2.5; shapeβ=4.5;        betad    = Beta(shapeα,shapeβ)
shapeα = 2.5; rateβ = 4.5;       gammad   = Gamma(shapeα,1/rateβ)

uvds = [unidd, bernd, bind, catd, geomd, hypgeomd, poissd, pascd,
        unicd, expd, normd, erld, cuachyd, chisqd,  td, fd, betad, gammad]
mvds = [multind]

x = 3
for d in uvds
    println("--------")
    println(d)
    println("Mean: $(mean(d))")
    println("Variance: $(var(d))")
    d != chisqd && println("Median: $(median(d))")
    println("Sample: $(rand(d))")
    println("PDF: $(pdf(d,x))")
    println("CDF: $(cdf(d,x))")
    println("20% quantile: $(quantile(d,0.2))")
end

xs = [3,12,5]
for d in mvds
    println("--------")
    println(d)
    println("Mean: $(mean(d))")
    println("Variance: $(var(d))")
    #println("Median: $(median(d))")
    println("Sample: $(rand(d))")
    println("PDF: $(pdf(d,xs))")
    #println("CDF: $(cdf(d,xs))")
    #println("20% quantile: $(quantile(d,0.2))")
end


#' ---
#' title: Problems on Graphs
#' ---

#' **Originally Contributed by**: Arpit Bhatia

#' In the mathematical discipline of graph theory, a number of problems can be solved by modelling them as optimization problems.
#' We will see some examples of such problems in the tutorial.
#' These problems are also sometimes referred to as combinatorial optimization problems as
#' they consist of finding an optimal object from a finite set of objects.

#' Let's first import all the packages we will be using for this tutorial.
#' We'll be plotting all the graphs we work with in this tutorial for which we will need some additional packages.

using JuMP
using GLPK
using GraphPlot
using LightGraphs
using Colors

#' ## Representing Graphs
#' For the purpose of this tutorial, we will represent graphs using adjacency matrices.
#' An adjacency matrix, sometimes also called the connection matrix, is a square matrix used to represent a finite graph.
#' Its rows and columns are labeled by the graph vertices,
#' with a 1 or 0 in position ($v_{i}$,$v_{j}$) according to whether $v_{i}$ and $v_{j}$ are adjacent or not.

#' ## Minimum Vertex Cover
#' Given a graph $G = (V, E)$, a vertex-cover $V' \subset V$ of $G$ is a collection of vertices such that
#' each edge in $E$ is incident to at least one of the vertices in $V'$.
#' The size of a vertex-cover $|V'|$ is the number of vertices present in the cover.
#' We wish to find the minimum vertex cover of $G$ i.e. a minimum size vertex cover.
#' We model this problem as an ILP by defining a decision variable $y_{v}$ for each vertex $v \in V$ and
#' a constraint for each edge $e \in E$ as follows:

#' $$
#' \begin{align*}
#' \min && \sum_{v \in V} y_{v} \\
#' s.t. && y_{u} + y_{v} \geq 1 && \forall \{u,v\} \in E \\
#' && y_{v} \in \{0,1\} && \forall v \in V
#' \end{align*}
#' $$

G = [
0 1 0 0 0 0;
1 0 1 1 0 0;
0 1 0 0 1 1;
0 1 0 0 1 0;
0 0 1 1 0 0;
0 0 1 0 0 0
]

g = SimpleGraph(G)

gplot(g)

#+

vertex_cover = Model(with_optimizer(GLPK.Optimizer))

@variable(vertex_cover, y[1:nv(g)], Bin)
@constraint(vertex_cover, [i = 1:nv(g), j = 1:nv(g); G[i,j] == 1], y[i] + y[j] >= 1)
@objective(vertex_cover, Min, sum(y))

optimize!(vertex_cover)
@show value.(y);

#+

membership = convert(Array{Int},value.(y)) # Change to Int
membership = membership + ones(Int, nv(g)) # Make the color groups one indexed
nodecolor = [colorant"red", colorant"blue"] # Blue to represent vertices in the cover
nodefillc = nodecolor[membership]
gplot(g, nodefillc = nodefillc)

#' ## Dominating Set
#' A dominating set in a graph $G = (V, E)$ is a set $S \subset V$ such that
#' for each vertex $v \in V$ either $v$ or one of its neighbour should be in $S$.
#' Note that for some vertex $u$, $u$ and its neighbour both can be present in $S$.
#' We wish to find the smallest dominating set for a graph.
#' We model this problem as an ILP by defining a decision variable $x_{v}$ for each vertex $v \in V$ along with
#' a constraint for its neighbourhood.

#' $$
#' \begin{align*}
#' \min && \sum_{v \in V} x_{v} \\
#' s.t. && \sum_{u \in N(v)}x_{u} \geq 1 && \forall v \in V \\
#' && x_{v} \in \{0,1\} && \forall v \in V
#' \end{align*}
#' $$

G = [
0 1 0 0 0 0 0 0 0 1 0 ;
1 0 1 0 0 0 0 0 0 0 1;
0 1 0 1 0 1 0 0 0 0 0;
0 0 1 0 1 0 0 0 0 0 0;
0 0 0 1 0 1 0 0 0 0 0;
0 0 1 0 1 0 1 0 0 0 0;
0 0 0 0 0 1 0 1 0 0 0;
0 0 0 0 0 0 1 0 1 0 1;
0 0 0 0 0 0 0 1 0 1 1;
1 0 0 0 0 0 0 0 1 0 1;
0 1 0 0 0 0 0 1 1 1 0
]

g = SimpleGraph(G)

gplot(g)

#+

dominating_set = Model(with_optimizer(GLPK.Optimizer))

@variable(dominating_set, x[1:nv(g)], Bin)
@constraint(dominating_set, [i = 1:nv(g)], sum(G[i,:] .* x) >= 1)
@objective(dominating_set, Min, sum(x))

optimize!(dominating_set)
@show value.(x);

#+

membership = convert(Array{Int},value.(x)) # Change to Int
membership = membership + ones(Int, nv(g)) # Make the color groups one indexed
nodecolor = [colorant"red", colorant"blue"] # Blue to represent vertices in the set
nodefillc = nodecolor[membership]
gplot(g, nodefillc = nodefillc)

#' ## Maximum Matching Problem
#' Given a graph $G = (V, E)$, a matching $M \subset E$ of $G$ is a collection of vertex disjoint edges.
#' The size of the matching $M$ is the number of edges present in $M$ i.e. $|M|$.
#' We wish to find the Maximum matching of $G$ i.e. a matching of maximum size.
#' We can solve this problem by modelling it as an integer linear program (ILP).
#' We define a decision variable $m_{e}$ for each edge $e \in E$ and a constraint for each vertex $u \in V$ as follows:

#' $$
#' \begin{align*}
#' \max && \sum_{e \in E} m_{e} \\
#' s.t. && \sum_{e \sim u} m_{e} \leq 1 && \forall u \in V \\
#' && m_{e} \in \{0,1\} && \forall e \in E
#' \end{align*}
#' $$

#' Let's now use JuMP to solve this problem for a sample graph.

G = [
0 0 0 0 1 0 0 0;
0 0 0 0 0 1 0 0;
0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 1;
1 0 0 0 0 1 0 1;
0 1 0 0 1 0 1 0;
0 0 1 0 0 1 0 1;
0 0 0 1 1 0 1 0;
]

g = SimpleGraph(G)

gplot(g)

#+

matching = Model(with_optimizer(GLPK.Optimizer))

@variable(matching, m[i = 1:nv(g), j = 1:nv(g)], Bin)
@constraint(matching, [i = 1:nv(g)], sum(m[i,:]) <= 1)
@constraint(matching, [i = 1:nv(g), j = 1:nv(g); G[i,j] == 0], m[i,j] == 0)
@constraint(matching, [i = 1:nv(g), j = 1:nv(g)], m[i,j] == m[j,i])
@objective(matching, Max, sum(m))

optimize!(matching)
@show value.(m);

#' The edges corresponding to the Matching are marked as one in the above matrix.

#' ## k-Coloring Problem
#' A k-coloring of a graph $G=(V,E)$ is a function $c: V \rightarrow \{1,2...k\}$ such that
#' $c(u) \neq c(v)$ for every edge $(u,v) \in E$. In other words, the numbers 1,2...k represent k colors,
#' and adjacent vertices must have different colours.
#' The goal of a graph coloring problem is to find a minimum number of colours needed to colour a graph.

#' We model this problem as an ILP by defining a variable decision variable $z_{i}$ for each colour we have available.
#' Given an upper bound $k$ on the number of colors needed,
#' we use $|V| \times k$ decision variables $c_{v,k}$ denoting if vertex $v$ is assigned color $k$.
#' Our model will become:

#' $$
#' \begin{align*}
#' \min && \sum_{i=1}^{k} z_{i} \\
#' s.t. && \sum_{i=1}^{k} c_{v,i} = 1 && \forall v \in V \\
#' && c_{u,i} + c_{v,i} \leq 1 && \forall (u,v) \in V, i \in \{1,2...k\} \\
#' && c_{v,i} \in \{0,1\} && \forall v \in V, i \in \{1,2...k\} \\
#' && z_{i} \in \{0,1\} && \forall i \in \{1,2...k\}
#' \end{align*}
#' $$

G = [
0 1 0 0 1 1 0 0 0 0;
1 0 1 0 0 0 1 0 0 0;
0 1 0 1 0 0 0 1 0 0;
0 0 1 0 1 0 0 0 1 0;
1 0 0 1 0 0 0 0 0 1;
1 0 0 0 0 0 1 0 0 1;
0 1 0 0 0 1 0 1 0 0;
0 0 1 0 0 0 1 0 1 0;
0 0 0 1 0 0 0 1 0 1;
0 0 0 0 1 1 0 0 1 0;
]

g = SimpleGraph(G)

gplot(g)

#+

k = nv(g)

k_colouring = Model(with_optimizer(GLPK.Optimizer))

@variable(k_colouring, z[1:k], Bin)
@variable(k_colouring, c[1:nv(g),1:k], Bin)
@constraint(k_colouring, [i = 1:nv(g)], sum(c[i,:]) == 1)
@constraint(k_colouring, [i = 1:nv(g), j = 1:nv(g), l = 1:k; G[i,j] == 1], c[i,l] + c[j,l] <= 1)
@constraint(k_colouring, [i = 1:nv(g), l = 1:k], c[i,l] <= z[l])

@objective(k_colouring, Min, sum(z))

optimize!(k_colouring)
@show value.(z);
@show value.(c);

#+

c = value.(c)
membership = zeros(nv(g))
for i in 1:nv(g)
    for j in 1:k
        if c[i,j] == 1
            membership[i] = j
            break
        end
    end
end
membership = convert(Array{Int},membership)

nodecolor = distinguishable_colors(nv(g), colorant"green")
nodefillc = nodecolor[membership]
gplot(g, nodefillc = nodefillc)


export Cubic, Spline, npatches, funk

# see http://mathworld.wolfram.com/CubicSpline.html

import Base: getindex, show

"""
`Cubic(a,b,c,d)` is a 3rd degree polynomial `a+bx+cx^2+dx^3`.
Use `f(x)` to evalue `f` at the value `x`.
"""
struct Cubic
    a::Number
    b::Number
    c::Number
    d::Number
end

(f::Cubic)(x::Number) = f.a + x * (f.b + x * (f.c + x * f.d))

"""
`f'` where `f` is a `Cubic` or `Spline` is the derivative
of `f`.
"""
Base.adjoint(f::Cubic) = Cubic(f.b, 2f.c, 3f.d, 0)

struct Spline
    patches::Array{Cubic,1}
    closed::Bool
end

is_closed(S::Spline) = S.closed

function Base.adjoint(S::Spline)
    plist = adjoint.(S.patches)
    return Spline(plist, S.closed)
end

"""
`Spline(vals,kind)` returns a cubic spline based on the values in `vals`.
The resulting spline `S` will have the property that `S(1)==y[1]`,
`S(2)==y[2]`, and so on up to `S(n)==y[n]` where `n` is the length of `y`.

+ If `kind` is `:open` then the second derivatives at the end points will be zero. (This is the default.)
+ If `kind` is `:closed` then we assume that we are interpolating a periodic function where `S(n+1)==S(1)`.
"""
function Spline(y::Array{T,1}, kind::Symbol = :open)::Spline where {T<:Number}
    n = length(y)
    if kind == :open
        @assert n > 2 "Open splines must have at least three points"
        return open_spline(y)
    end
    if kind == :closed
        @assert n > 3 "Closed splines must have at least four points"
        return closed_spline(y)
    end

    error("Spline type must be :open or :closed, not $kind")
end

function npatches(S::Spline)
    return length(S.patches)
end

function show(io::IO, S::Spline)
    adjective = is_closed(S) ? "Closed" : "Open"
    print(io, "$adjective spline with $(npatches(S)) patches")
end

getindex(S::Spline, idx::Int) = S.patches[idx]

"""
`funk(S)` converts the Spline `S` into a callable function
(e.g., that can be passed to `plot`).
"""
function funk(S)::Function
    return x -> S(x)
end

function (S::Spline)(x::Real)
    np = npatches(S)

    if is_closed(S)

        p = Int(floor(x))
        x = mod(x, np)
        p = Int(floor(x))

        if p == 0
            p = np
            x += np
        end
        f = S[p]
        return f(x - p)
    end

    # open spline
    p = Int(floor(x))
    if x < 1
        p = 1
    end

    if p > np
        p = np
    end
    f = S[p]
    return f(x - p)
end

function open_spline(y::Array{T,1})::Spline where {T<:Number}
    n = length(y)
    M = zeros(n, n)
    for i = 1:n
        M[i, i] = 4
    end
    M[1, 1] = 2
    M[n, n] = 2

    for i = 1:n-1
        M[i, i+1] = 1
        M[i+1, i] = 1
    end

    rhs = zeros(T, n)
    rhs[1] = 3 * (y[2] - y[1])
    for k = 2:n-1
        rhs[k] = 3 * (y[k+1] - y[k-1])
    end
    rhs[n] = 3 * (y[n] - y[n-1])

    D = M \ rhs

    a = zeros(Number, n - 1)
    b = zeros(Number, n - 1)
    c = zeros(Number, n - 1)
    d = zeros(Number, n - 1)

    for j = 1:n-1
        a[j] = y[j]
        b[j] = D[j]
        c[j] = 3 * (y[j+1] - y[j]) - 2D[j] - D[j+1]
        d[j] = 2 * (y[j] - y[j+1]) + D[j] + D[j+1]
    end
    return Spline([Cubic(a[i], b[i], c[i], d[i]) for i = 1:n-1], false)
end

function closed_spline(y::Array{T,1})::Spline where {T<:Number}
    yy = copy(y)
    n = length(y)
    prepend!(yy, y[end-3:end])
    append!(yy, y[1:4])

    S = open_spline(yy)

    plist = S.patches[5:end-3]
    return Spline(plist, true)

end