### A Pluto.jl notebook ### # v0.19.26 using Markdown using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end # ╔═╡ bbe20904-d70a-438d-b46a-889ddfb8bab3 begin using Plots # pour le tracé de figures using Statistics # pour mean et std (en autres) using PlutoUI # pour les objets Pluto using LinearAlgebra # pour les matrices identité using StatsPlots using Distributions using MAT using DSP gr() TableOfContents(depth=4) end # ╔═╡ e08d7569-68d5-4da6-b8fa-085ed6a312f6 html""" """ # ╔═╡ 63ae9b00-344d-4726-8d21-a0bdc75ee8be html"""
Traitement des données audio-visuelles
Laurent Fainsin
2021 - 2022
""" # ╔═╡ f7cdde7d-884d-4116-9d40-0b2f68e71e6a md""" # TP1/TP2 - Courbes de bézier """ # ╔═╡ 8cd04c88-4ea4-4594-b0ab-a145096b3122 """ Renvoie un [polynome de Bernstein](https://en.wikipedia.org/wiki/Bernstein_polynomial). ###### Args: - i : le degré selectionné - d : le(s) degré(s) du polynome - x : le(s) point(s) que l'on souhaite évaluer """ function bernstein(i::Int, d, x) return binomial(d, i) .* x .^ i .* (1 .- x) .^ (d - i) end # ╔═╡ 3a57871a-8ccf-11ec-3c6c-d525f4e8b5c2 """ Renvoie une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve). ###### Args: - β_0 : le premier point de controle de la courbe - β : les points de contrôles intermédiaire de la courbe - β_d : le dernier point de contrôle de la courbe - x : le(s) point(s) que l'on souhaite évaluer """ function bezier(β_0::Number, β::AbstractArray, β_d::Number, x) d = length(β) + 1 y = β_0 * (1 .- x) .^ d + β_d * x .^ d for i = 1:d-1 y += β[i] * bernstein(i, d, x) end return y end # ╔═╡ 513cf0e8-b7db-447c-b04a-a2e2fa17fb32 """ Renvoie une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) bruité selon une [distribution normale](https://en.wikipedia.org/wiki/Normal_distribution). ###### Args: - β_0 : le premier point de controle de la courbe - β : les points de contrôles intermédiaire de la courbe - β_d : le dernier point de contrôle de la courbe - x : le(s) point(s) que l'on souhaite évaluer - σ : l'écart-type de la distribution normale """ function bezier_bruitee(β_0::Number, β::AbstractArray, β_d::Number, x, σ::Number) return bezier(β_0, β, β_d, x) + σ * randn(size(x)) end # ╔═╡ 97fba57b-8d2a-49c9-a18a-58eb2fe651eb """ Renvoie la régression d'une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) par optimisation du [problème des moindres carrés](https://en.wikipedia.org/wiki/Least_squares). ###### Args: - D_app : matrice contenant les points à régresser - β_0 : le premier point de controle de la courbe - β_d : le dernier point de contrôle de la courbe - d : le degré du la courbe de Bézier souhaité """ function moindres_carres(D_app::Vector, β_0::Number, β_d::Number, d::Int)::AbstractArray x, y = D_app B = y .- β_0 .* (1 .- x) .^ d .- β_d .* (x .^ d) A = zeros(length(x), d - 1) for i = 1:(d-1) A[:, i] = bernstein(i, d, x) end return A \ B end # ╔═╡ 78784cae-f749-4a0f-89cc-46dfa4994d3a """ Renvoie la régression d'une [courbe de Bézier](https://en.wikipedia.org/wiki/Bézier_curve) par optimisation du [problème des moindres carrés](https://en.wikipedia.org/wiki/Least_squares) écrêtés. ###### Args: - D_app : matrice contenant les points à régresser - β_0 : le premier point de controle de la courbe - β_d : le dernier point de contrôle de la courbe - d : le degré du la courbe de Bézier souhaité - λ : le terme de pénalisation, "hyper-paramètre" """ function moindres_carres_ecretes(D_app::Vector, β_0::Number, β_d::Number, d::Int, λ::Number)::AbstractArray x, y = D_app B = y .- β_0 .* (1 .- x) .^ d .- β_d .* (x .^ d) A = zeros(length(x), d - 1) for i = 1:(d-1) A[:, i] = bernstein(i, d, x) end slope = (β_d - β_0) / (last(x) - first(x)) beta_barre = slope .* (1/d:1/d:1-1/d) .+ β_0 C = B .- A * beta_barre delta_chapeau = (A' * A + λ .* I(d - 1)) \ (A' * C) return beta_barre .+ delta_chapeau end # ╔═╡ f2f61669-6cbd-460d-9a48-454634f86579 Markdown.MD(Markdown.Admonition("warning", "Interactivité !", [md"Attention l'utilisation des sliders pour jouer avec les paramètres des figures (TP1/TP2) nécessite d'utiliser [Pluto.jl](https://github.com/fonsp/Pluto.jl). Pour ouvrir ce notebook, vous pouvez simplement cliquer en haut à droite de la page sur \"Edit or run this notebook\". Sinon vous pouvez toujours utiliser le service en ligne Binder, mais c'est très lent."])) # ╔═╡ cf014e6b-9e74-4abf-9532-540f4bb6f43f begin σ_slider = @bind σ Slider(0:0.05:1, default=0.6, show_value=true) # Points de contrôles, degré = 5 β_0 = 115 β_d = 123 β = [116, 120, 123.5, 114.5] d_exact = length(β) + 1 md""" ## Génération de nos données de travail σ: $(σ_slider) Il nous faut générer des données avec lesquelles nous allons travailler par la suite. On construit alors des points de contrôle à partis desquels nous allons générer une courbe de bézier (de degré $(d_exact)) et des échantillons pour notre apprentissage et nos tests. """ end # ╔═╡ 287bac5f-8932-4d8f-a114-39f4e071ba26 begin gr() # Calcul du modèle exact x_exact = LinRange(0, 1, 50) y_exact = bezier(β_0, β, β_d, x_exact) # Calcul des données d'apprentissage x_app = LinRange(0, 1, 100) y_app = bezier_bruitee(β_0, β, β_d, x_app, σ) D_app = [x_app, y_app] # Calcul des données de test x_test = LinRange(0, 1, 200) y_test = bezier_bruitee(β_0, β, β_d, x_test, σ) D_test = [x_test, y_test] # Tracé des données générées figure = plot(x_exact, y_exact, label="exact", linewidth=2, legend=:topleft) scatter!(x_app, y_app, label="apprentissage", opacity=0.3, markershape=:xcross) scatter!(x_test, y_test, label="test", markersize=2, opacity=0.2, markershape=:xcross) scatter!(0:1/d_exact:1, [β_0; β; β_d], label="points de controles") xlabel!("x") xlims!(-0.01, 1.01) xticks!(0:0.1:1) ylabel!("y") ylims!(114, 124) title!("σ=" * string(σ)) end # ╔═╡ e1b0bacc-a173-4084-bb5f-3fbd63527c23 begin d_slider = @bind d Slider(1:1:20, default=5, show_value=true) md""" ## Régression par les moindres carrés d: $(d_slider) On peut dans un premier temps utiliser les moindres carrés pour effectuer une régression de la courbe de bézier, et ainsi retrouver les points de contrôle définis précédemment. On cherche à résoudre le problème suivant: $A \beta^\top = B$ Au moindres carrés, on a: $\beta^\top = A^\dagger B = (A^\top A)^{-1} A^\top B$ """ end # ╔═╡ 1ae5bc6d-16c4-40cb-846e-3b0e177fd0cf begin gr() # Régression par les moindres carrés β_estime = moindres_carres(D_test, β_0, β_d, d) y_estime = bezier(β_0, β_estime, β_d, x_app) # Tracé de la regression plot(x_app, y_estime, linewidth=2, label="estimation", legend=:bottomright) plot!(x_exact, y_exact, label="exact") scatter!(x_app, y_app, label="apprentissage", opacity=0.2, markershape=:xcross) xlabel!("x") xlims!(-0.01, 1.01) xticks!(0:0.1:1) ylabel!("y") ylims!(114, 124) title!("d=" * lpad(d, 2, "0") * ", σ=" * string(σ)) end # ╔═╡ b3634cc1-fb5f-4b7b-bfa3-08d1fb787c5f md""" On observe alors que plus $\sigma$ (le bruit) est élevé, plus la régression sera eloigné de la véritable courbe. De même on remarque que plus le degré $d$ de la regression est élevé, plus la courbe estimée colle aux différents points de notre base d'apprentissage, mais on observera que celle-ci s'éloigne tout de même de la courbe originale. """ # ╔═╡ 73ed5f0e-4298-4308-bcb8-7c1245ebf0f5 md""" ### Calcul de l'erreur de l'estimation Nous pouvons trouver l'erreur de notre approximation en calculant l'erreur quadratique moyenne sur une série de degrés. Nous disposons de plusieurs méthodes pour calculer cette erreur: """ # ╔═╡ c0615490-3d43-4c42-9ac6-c4fdd59aae7f md""" On observe alors que l'erreur d'apprentissage est décroissante, celle-ci tend vers 0, et atteint 0 pour $d=\text{nb}_{\text{app}}$. Intuitivement la meilleure valeur pour $d$ semble être le minimum des erreurs de généralisation ou de leave-one-out. """ # ╔═╡ cc938f64-41f9-478b-a136-ae0cc55b5f48 function erreur_apprentissage(D_app, β_0, β_d, d) x, y = D_app β = moindres_carres(D_app, β_0, β_d, d) estimation = bezier(β_0, β, β_d, x) return mean((estimation - y) .^ 2) end # ╔═╡ aec0ff6e-ac6a-4104-83c1-f70e254602b9 function erreur_generalisation(D_test, D_app, β_0, β_d, d) x, y = D_test β = moindres_carres(D_app, β_0, β_d, d) estimation = bezier(β_0, β, β_d, x) return mean((estimation - y) .^ 2) end # ╔═╡ dbffcc35-ba67-4468-b1b5-1c38a0fd971e function erreur_leave_one_out(D_app, β_0, β_d, d) x, y = D_app n = length(x) VC = 0 for j = 1:n D_loo = [ [x[1:j-1]; x[j+1:end]], [y[1:j-1]; y[j+1:end]] ] β = moindres_carres(D_loo, β_0, β_d, d) estimation = bezier(β_0, β, β_d, x[j]) VC += (y[j] - estimation) .^ 2 end return VC / n end # ╔═╡ d969e49e-0a0c-4bdf-aba2-835586c87e7f begin gr() degres = 2:15 erreurs_apprentissage = zeros(length(degres)) erreurs_generalisation = zeros(length(degres)) erreurs_leave_one_out = zeros(length(degres)) for (i, d) = enumerate(degres) # Calcul de l'erreur d'apprentissage en fonction de d err_app = erreur_apprentissage(D_app, β_0, β_d, d) erreurs_apprentissage[i] = err_app # Calcul de l'erreur de généralisation en fonction de d err_gen = erreur_generalisation(D_test, D_app, β_0, β_d, d) erreurs_generalisation[i] = err_gen # Calcul de la validation croisée Leave-one-out err_loo = erreur_leave_one_out(D_app, β_0, β_d, d) erreurs_leave_one_out[i] = err_loo end plot(degres, erreurs_apprentissage, linewidth=2, label="apprentissage") plot!(degres, erreurs_generalisation, linewidth=2, label="généralisation") plot!(degres, erreurs_leave_one_out, linewidth=2, label="leave-one-out") xlabel!("d") xticks!(degres) ylabel!("erreur") title!("σ=" * string(σ)) end # ╔═╡ ae8a3f9b-12cf-4802-8ae5-31546d82516d md""" ### Estimation de $d$ et $\sigma$ Le calcul de ces erreurs nous permet d'estimer le meilleur degré $d$ à sélectionner pour que notre modèle soit le plus exact: """ # ╔═╡ 7960408a-d922-43e2-9a61-4aaf0c9e6a39 begin # Estimation du degré de la courbe par dérivée de l'apprentissage (ghetto) local d_estime_app = argmax(diff(erreurs_apprentissage)) local σ_estime_app = std(erreurs_apprentissage) # Estimation du degré de la courbe et de σ, par généralisation local d_estime_gen = degres[argmin(erreurs_generalisation)] local σ_estime_gen = std(erreurs_generalisation) # Estimation du degré de la courbe et de σ, par leave-one-out local d_estime_loo = degres[argmin(erreurs_leave_one_out)] local σ_estime_loo = std(erreurs_leave_one_out) Markdown.MD( Markdown.Admonition( "info", "Résultats", [Markdown.parse(""" ∇²Apprentissage : d=$(d_estime_app), σ=$(round(σ_estime_app, digits=2)) (~broken) Généralisation : d=$(d_estime_gen), σ=$(round(σ_estime_gen, digits=2)) Leave-one-out : d=$(d_estime_loo), σ=$(round(σ_estime_loo, digits=2)) """)] ) ) end # ╔═╡ b56c3502-4dd9-4446-acd9-dcb0c667803f md""" On peut par la même occasion essayer de calculer l'écart-type de nos données, et le comparer au véritable sigma=$(σ). Les estimations ne sont pas très précises. """ # ╔═╡ cde13c7c-fbc2-4a8d-9b82-7607d71bb4b1 begin gr() n = 1000 degre = 5 betas_estime = zeros(n, 4) x_rng = LinRange(0, 1, 100) for i = 1:n y_rng = bezier_bruitee(β_0, β, β_d, x_rng, σ) D_rng = [x_rng, y_rng] betas_estime[i, :] = moindres_carres(D_rng, β_0, β_d, degre) end A = zeros(length(x_rng), degre - 1) for i = 1:(degre-1) A[:, i] = bernstein(i, degre, x_rng) end σ_norm = diag(σ^2 .* pinv(A' * A)) colors = distinguishable_colors(degre - 1) plot() for (i, b) = enumerate(β) histogram!(betas_estime[:, i], bins=:scott, label=false, normed=true, opacity=0.25, fillcolor=colors[i]) plot!(Normal(b, σ_norm[i]), color=colors[i], label="β[" * string(i) * "]", linewidth=3) end xlabel!("β") xlims!(105, 135) ylims!(0, 1) title!("σ=" * string(σ)) end # ╔═╡ 76279a22-3afe-46e1-829f-88f5dddfd55c md""" ### Vérifions que notre modèle soit non biaisé On peut montrer que le vecteur de paramètres estimé en moindres carrés est distribué selon la loi normale suivante: $$\beta \hookrightarrow \mathcal{N} ( \beta^*, \sigma^2 ( A^\intercal A )^{-1})$$ On trace alors sur la figure suivante, avec un tracé continu la distribution théorique des $\beta$, et via un histogramme la distribution que l'on obtient par estimation aux moindres carrés (sur un grand nombre de points, n=1000) """ # ╔═╡ a8843a99-cd5d-47fa-810b-68b56e405af9 md""" On observe bien que les tracés discrets et continus se superposent, on en déduit que notre estimation est bien non biaisée. """ # ╔═╡ c3f3a0c3-8523-43aa-8a8a-589f567399c9 begin λ_slider = @bind λ Slider(0:0.01:0.1, default=0.05, show_value=true) md""" ## Régression par les moindres carrés écrêtées λ: $(λ_slider) On observe que via les moindres carrés classiques, notre régression a souvent tendance à [overfitter](https://fr.wikipedia.org/wiki/Surapprentissage) les points d'apprentissage. Pour remédier à ce problème, nous pouvons introduire un hyperparamètre $\lambda$ qui nous permettra de pénaliser l'overfitting (par régularisation). """ end # ╔═╡ f60fbae0-a6bd-4791-b38b-9e29ae801a07 begin gr() # Régression par les moindres carrés écrétés β_estime_ecrete = moindres_carres_ecretes(D_test, β_0, β_d, 10, λ) y_estime_ecrete = bezier(β_0, β_estime_ecrete, β_d, x_app) # Tracé de la regression plot(x_app, y_estime_ecrete, linewidth=2, label="estimation", legend=:bottomright) plot!(x_exact, y_exact, label="exact", opacity=0.5) scatter!(x_app, y_app, label="apprentissage", opacity=0.5, markershape=:x) xlabel!("x") xlims!(-0.01, 1.01) xticks!(0:0.1:1) ylabel!("y") ylims!(114, 124) title!("d=" * lpad(d, 2, "0") * ", σ=" * string(σ) * ", λ=" * rpad(λ, 4, "0")) end # ╔═╡ b95121b9-4b58-4086-bbd8-ecd2893060dd md""" On remarque alors que plus $\lambda$ est grand, plus la courbe estimée aura tendance à être simple, pour des $\lambda$ très élevés, la courbe tend vers une droite entre $\beta_0$ et $\beta_d$. """ # ╔═╡ 3ff18976-beb4-45ad-aa29-d511e5d3ad0a md""" ### Calcul de l'erreur de l'estimation Puisque nous sommes désormais capables de trouver le degré optimal à selectionner pour notre regression via l'etude précédente, nous pouvons désormais nous focaliser sur l'erreur de notre approximation en faisant varier $\lambda$. """ # ╔═╡ acbab47e-2ab5-443a-8d78-f597a4ca08ed md""" On estime alors le meilleur $\lambda$ à selectionner en minimisant l'erreur: """ # ╔═╡ c563818e-d117-47ce-abeb-5b048edad64e function erreur_leave_one_out_bis(D_app, β_0, β_d, d, λ) x, y = D_app n = length(x) VC = 0 for j = 1:n D_loo = [ [x[1:j-1]; x[j+1:end]], [y[1:j-1]; y[j+1:end]] ] β = moindres_carres_ecretes(D_loo, β_0, β_d, d, λ) estimation = bezier(β_0, β, β_d, x[j]) VC += (y[j] - estimation) .^ 2 end return VC / n end # ╔═╡ 650ab9f4-581b-4190-8dd0-91c6d4c86b6b function erreur_leave_one_out_ter(D_app, beta_0, beta_d, d, lambda) x, y = D_app A = zeros(length(x), d - 1) for i = 1:(d-1) A[:, i] = bernstein(i, d, x) end S = A * ((A' * A + lambda * I(d - 1)) \ A') beta = moindres_carres_ecretes(D_app, beta_0, beta_d, d, lambda) bidule = ((y - bezier(beta_0, beta, beta_d, x)) ./ (1 .- diag(S))) .^ 2 return mean(bidule) end # ╔═╡ 1b88eacd-754b-4b6b-a8e0-dd35ae37f248 begin gr() lambdas = 0.01:0.001:0.1 erreurs_leave_one_out_ter = zeros(length(lambdas)) for (i, l) = enumerate(lambdas) err_loo = erreur_leave_one_out_ter(D_app, β_0, β_d, d, l) erreurs_leave_one_out_ter[i] = err_loo end plot(lambdas, erreurs_leave_one_out_ter, linewidth=2, label="leave-one-out") xlabel!("λ") ylabel!("erreur") title!("σ=" * string(σ)) end # ╔═╡ 230c1126-6717-4a93-9013-5f0c15616904 begin # Estimation de λ et de σ, par leave-one-out local λ_estime_loo = lambdas[argmin(erreurs_leave_one_out_ter)] Markdown.MD( Markdown.Admonition( "info", "Résultats", [Markdown.parse(""" Leave-one-out: λ=$(λ_estime_loo) """)] ) ) end # ╔═╡ 5974ceb3-1e82-4183-9dca-35ccd6b9a9ba md""" ## Courbes de Bézier couplées Il peut nous être parfois amené à combiner plusieurs courbes de bézier en une seule (pour du tracé/dessin vectoriel par exemple). Voyons un exemple en couplant deux courbes de Bézier (modélisant deux bords du contour d'une flamme). """ # ╔═╡ c9e530b7-f5f6-4905-8c6c-69ea2440f57d md""" Pour coupler nos courbes, on couple simplement nos deux systèmes de la manière suivante: Soit $x_g$, $x_d$ et $y$ les variables nous permettant de décrire respectivement le bord gauche et le bord droit de la flamme. Posons ```math X = \begin{bmatrix} x_g \\ x_d \end{bmatrix} , \quad E = \begin{bmatrix} B_1^d(y_1) & \cdots & B_{d-1}^d(y_1) & 0 & \cdots & 0 & B_d^d(y_1) \\ \vdots & \ddots & \vdots & \vdots & & \vdots & \vdots \\ B_1^d(y_n) & \cdots & B_{d-1}^d(y_n) & 0 & \cdots & 0 & B_d^d(y_n) \\ 0 & \cdots & 0 & B_1^d(y_1) & \cdots & B_{d-1}^d(y_1) & B_d^d(y_1) \\ \vdots & & \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & \cdots & 0 & B_1^d(y_n) & \cdots & B_{d-1}^d(y_n) & B_d^d(y_n) \end{bmatrix} , \quad F = X - \begin{bmatrix} \beta_0 B_0^d(y_1) \\ \vdots \\ \beta_0 B_0^d(y_n) \\ \gamma_0 B_0^d(y_1) \\ \vdots \\ \gamma_0 B_0^d(y_n) \\\end{bmatrix} ``` Il nous suffit alors de résoudre le système $E Y = F$ (où $Y$ est notre flamme). """ # ╔═╡ 67a5b4cc-00dd-4f8f-a408-27f1d8c60e7c md""" ### Simulation de silhouettes On modélisant les $\beta$ obtenus via les figures précédentes par une loi normale, nous sommes en mesure de _simuler_ de [nouvelles flammes](https://c.tenor.com/rdkHWmsaP5sAAAAC/inflatable-tube-man-air-dancer.gif). Cependant, on observe que les écarts-types trouvé sont plutôt grands. (Ici, les coefficients ont été atténués pour des raisons visuelles.) """ # ╔═╡ 8655b8fd-ef08-441f-9186-e2febce6e8f1 md""" Une meilleure estimation serait de modéliser séparement tous les indices pairs et impairs de $\beta$ séparement, comme le laisse suggérer la figure suivante: """ # ╔═╡ 475aecd7-123f-4e4a-b004-90c2a8a951d8 md""" On observe que les $\beta$ "oscillent", une estimation par loi normale semble donc peu adaptée, puisque cela génère de grands écart-types. """ # ╔═╡ fac7b990-552e-4353-8264-ba0840a95383 function moindres_carres_bis(d, y, bords_g, beta_0, bords_d, gamma_0) x = [bords_g; bords_d] F = x .- [beta_0 .* bernstein(0, d, y); gamma_0 .* bernstein(0, d, y)] E_block = zeros(length(y), d) for i = 1:d E_block[:, i] = bernstein(i, d, y) end E = [ E_block[:, 1:d-1] zeros(length(y), d - 1) E_block[:, d] zeros(length(y), d - 1) E_block ] return E \ F end # ╔═╡ 27a1f0cc-a6bc-417e-9c58-6b63172f753f begin gr() # chargement des données du TP à partir du fichier .mat file = matopen("donnees.mat") y = read(file, "y") bords = read(file, "bords") gamma_0 = read(file, "gamma_0") beta_0 = read(file, "beta_0") local d = Int(read(file, "n")) close(file) local flame = @animate for k in 1 : 10 X_estime = moindres_carres_bis(d, y, bords[:, 1, k], beta_0, bords[:, 2, k], gamma_0)' beta_estime = [X_estime[1:d-1]; X_estime[2*d-1]] gamma_estime = [X_estime[d:2*(d-1)]; X_estime[2*d-1]] x_gauche = bezier(beta_0, beta_estime[1:end-1], beta_estime[end], y) x_droite = bezier(gamma_0, gamma_estime[1:end-1], gamma_estime[end], y) scatter(y, bords[:, 1, k], color=:crimson, markersize=2, opacity=0.25, label=false) scatter!(y, bords[:, 2, k], color=:crimson, markersize=2, opacity=0.25, label=false) plot!(y, x_gauche, color=:crimson, label=false) plot!(y, x_droite, color=:crimson, label=false) xlabel!("y") xlims!(-0.01, 1.01) ylabel!("x") ylims!(55, 160) title!("k=" * lpad(k, 2, "0")) end gif(flame, fps=10); end # ╔═╡ e16bb608-d97b-40eb-bf6b-4199ee4d1926 begin gr() local anim = @animate for k in 1 : 1 : 10 X_estime = moindres_carres_bis(d, y, bords[:, 1, k], beta_0, bords[:, 2, k], gamma_0)' beta_estime = [X_estime[1:d-1]; X_estime[2*d-1]] plot(beta_estime, label="betas") xlabel!("beta") ylabel!("estimation") ylims!(20, 200) title!("k=" * lpad(k, 2, "0")) end gif(anim, fps=5) end # ╔═╡ 4bcfb185-4499-422d-9439-6ca4e30c4846 function estimation_lois_n(x) return mean(eachrow(x)), std(x, dims=1)[:] end # ╔═╡ 174dbb25-12ba-460d-a905-8223f8241964 function simulation(y, β_0, γ_0, moyennes, ecarts_types, d) β = ecarts_types[1:d-1] / 5 .* randn(d - 1) .+ moyennes[1:d-1] γ = ecarts_types[d:2*d-2] / 5 .* randn(d - 1) .+ moyennes[d:2*d-2] γ_d = ecarts_types[2*d-1] / 5 * randn() + moyennes[2*d-1] β_d = γ_d x_gauche = bezier(β_0, β, β_d, y) x_droite = bezier(γ_0, γ, γ_d, y) return [x_gauche, x_droite] end # ╔═╡ 489676a6-b6cb-46dc-9898-feedcc2b61dd begin gr() local d = 4 X = moindres_carres_bis(d, y, bords[:, 1, :], beta_0, bords[:, 2, :], gamma_0)' moyennes, ecarts_types = estimation_lois_n(X) # Simulation de silhouettes par tirages aléatoires local flame = @animate for k in 1 : 1 : 10 x_g, x_d = simulation(y, beta_0, gamma_0, moyennes, ecarts_types, d) plot(x_d, y, label=false, color=:crimson) plot!(x_g, y, label=false, color=:crimson) xlabel!("x") xlims!(55, 160) ylabel!("y") ylims!(-0.01, 1.01) end gif(flame, fps=10) end # ╔═╡ 59be55be-5847-4fa1-a4f6-ef8e0658da13 md""" # TP3 - Ellipses Dans l'esprit des TP1 et TP2, on se concentre désormais sur l'estimation d'ellipses à partir d'un nuage de points. """ # ╔═╡ 2e002135-2a74-47bb-92a6-520d84e85bf3 md""" ## Cas n=1 """ # ╔═╡ 764c0716-5dd2-4d3c-9489-1dd92d29d7c7 md""" ### Estimation par maximum de vraisemblance Tout comme précédemment, la méthode la plus simple, mais non la plus efficace, est simplement d'essayer aléatoirement un grand nombre d'ellipses et de voir celle qui colle le mieux à notre nuage de points. Mathématiquement on cherche à minimiser la vraisemblance: ```math L_\text{p}(D_{app}) = \prod^{n_\text{app}}_{i=1} f_\text{P} (P_i) ``` avec: ```math f_\text{P}(P_i) = \frac1{\sigma \sqrt{2\pi}} \exp\left\{{- \frac{r_\text{P}(P_i)^2}{2\sigma^2}}\right\} ``` En reformulant le problème, on minimise la somme: ```math \min_\text{P} \left\{ \sum^{n_{app}}_{i=0} r_\text{P} (P_i)^2 \right\} ``` | | | | :---------------------------------: | :--------------------------------: | | $(Resource("content/TP3/exo1app.png")) | $(Resource("content/TP3/exo1mv.png")) | """ # ╔═╡ 274dd1f3-2a8c-4d4f-b8e2-a61e2f7bdef4 md""" ### Estimation par résolution d’un système linéaire Si l'on est sûr que notre nuage de point décrit une unique ellipse, on peut alors encore plus simplement résoudre le système linéaire: ```math \alpha x^2 + \beta x y + \gamma y^2 + \delta x + \epsilon y + \phi = 0 ``` On peut poser ce problème matriciellement: ```math A X = O_{n_\text{app}} ``` avec: ```math X = \begin{bmatrix} \alpha \\ \beta \\ \gamma \\ \epsilon \\ \phi \end{bmatrix} , \quad A = \begin{bmatrix} x_0^2 & x_0 y_0 & y_0^2 & x_0 & y_0 & 1 \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ x_{n_\text{app}}^2 & x_{n_\text{app}} y_{n_\text{app}} & y_{n_\text{app}}^2 & x_{n_\text{app}} & y_{n_\text{app}} & 1 \\ 1 & 0 & 1 & 0 & 0 & 0 \end{bmatrix} , \quad O_{n_\text{app}} = \begin{bmatrix} 0 \\ \vdots \\ 0 \\ 1 \end{bmatrix} ``` | | | | :---------------------------------: | :--------------------------------: | | $(Resource("content/TP3/exo2app.png")) | $(Resource("content/TP3/exo2mc.png")) | """ # ╔═╡ e7ac36db-6496-4f0b-b961-1f180ca3622d md""" ## Cas n > 1 """ # ╔═╡ d97fd9ab-1422-4c39-85e6-d5306c690310 md""" ### Estimation par maximum de vraisemblance Pour passer à l'estimation de plusieurs ellipses on change simplement nos formules: ```math f(P) = \sum^{N_e}_{i=0}\frac{\pi_i}{\sigma_i \sqrt{2\pi}} \exp\left\{{- \frac{r_{\text{P}_i}(P_i)^2}{2\sigma_i^2}}\right\} ``` La maximisation de la log vraisemblance s'écrit alors: ```math \max_\text{P} \left\{ \ln \prod^{n_\text{app}}_{i=1} f(\text{P}) \right\} ``` Pour améliorer nos résultats, on peut séparer les points en classes de telle manière que les points les plus proches d'une même ellipse soient dans la même classe. En re-estimant nos ellipses, mais cette fois-ci classe par classes, on obtient un résultat satisfaisant. """ # ╔═╡ 6ce5a769-a05b-4a72-b2a6-46f61c530c3a html"""
données vraisemblance séparation
""" # ╔═╡ 1a31ebb3-b512-45b9-9f55-2a7b173ff2c7 md""" ### Estimation par l’algorithme EM Une manière d'obtenir un résultat itérativement est d'utiliser un algorithme EM. Celui-ci consiste au calcul des probabilités d’appartenance aux classes des points d’apprentissage: ```math \mathcal{P}_k (P_i) = \frac { \displaystyle \frac{\pi_k}{\sigma_k} \exp\left\{{- \frac{r_{\text{P}_k}(P_i)^2}{2\sigma_k^2}}\right\} } { \displaystyle \sum^{N_e}_{i=0}\frac{\pi_i}{\sigma_i} \exp\left\{{- \frac{r_{\text{P}_i}(P_i)^2}{2\sigma_i^2}}\right\} } ``` À la mise à jour des proportions du mélange: ```math \pi_k = \frac1{n_{app}} \sum^{n_{app}}_{i=1} \mathcal{P}_k (P_i) ``` Et à la résolution en moindres carrés pondérés des points de chaque classe. """ # ╔═╡ 05a64770-4015-438e-83ee-2d84d2277055 html"""
données vraisemblance EM
Voici deux autres exemples, avec cette fois-ci un plus grand nombre d'ellipses:
données EM
On observe que l'algorithme aura tendance à parfois exploser numériquement. """ # ╔═╡ 5a7ec049-1092-4096-b5d9-4d2f84c6be41 md""" # TP4 - Segmentation """ # ╔═╡ 492cba29-1b5f-4f31-80e6-32dcab025f2f md""" Notre objectif dans ce TP est de procéder à la segmentation d'une image par classification. Notre image (B&W) fil rouge sera celle-ci: ![50%](content/TP4/image_BW.png) Cette image comporte 4 classes simples (gaussiennes, avec bruit) qu'il nous faudra retrouver. """ # ╔═╡ 830a7a78-0cb1-4ed1-906e-dd89bad6150f md""" ## Approche supervisée Si l'on dispose d'un expert, il est simple de lui demander d'échantillonner manuellement l'image pour que l'on puisse ainsi procéder derrière à une classification et à une segmentation. ![50%](content/TP4/expert_BW.png) Une première méthode naïve serait de procéder par maximimsation de la vraisemblance, mais cette méthode, en plus d'être stochastique, ne fournis pas des résultats très satisfaisants (~90%). ![50%](content/TP4/exo1mv.png) Une amélioration consiste alors à utiliser le résultat précédent comme base à un recuit simulé. ![50%](content/TP4/exo1.webp) On remarque que cette approche améliore grandement notre estimation, il est possible d'obtenir de très bons résultats (>99.9%) si l'on tweak bien les paramètres de nos itérations. """ # ╔═╡ fb735670-d29b-43bd-a88b-ff79d489e0b0 md""" ## Approche non supervisé Si on n'a pas d'expert, ou si on veut faire des économies, on peut essayer d'inférer les classes de notre image à partir de son histogramme. ![50%](content/TP4/exo2hist4N_2B_0.99A.png) En effet, on remarque facilement sur l'histogramme de notre image 4 pics (4 gaussiennes) qui correspondent à nos 4 classes. Pour déterminer les paramètres de ces gaussiennes on procède par estimation à posteriori (on tire des combinaisons de gaussiennes au hasard et on prend celle qui correspond le mieux). Voici l'image correspondante à cet histogramme: ![50%](content/TP4/exo2mv.png) On obtient un histogramme satisfaisant, qui implique une bonne segmentation de notre image, mais comme précédemment, on peut soumettre ce résultat au recuit simulé pour améliorer notre segmentation. ![50%](content/TP4/recuit_MAP_4N_2B_0.99A.webp) """ # ╔═╡ 05ee0bd3-320d-4d8c-993e-f2e587d78dd8 md""" ## Avec de la couleur c'est mieux Si l'on souhaite classifier une image en couleur et non en dégradé de gris, on applique la même logique que précédemment mais en dimension plus élevée (ici en dimension 3, puisque notre image colorée contient 3 canaux de couleur, le rouge, le vert et le bleu). image à segmenter: ![50%](content/TP4/cellules.jpg) selection de l'expert: ![50%](content/TP4/exo3expert.png) maximum de vraisemblance: ![50%](content/TP4/exo3mv.png) recuit simulé: ![50%](content/TP4/recuit_exo3.webp) """ # ╔═╡ c89378e2-424e-4a46-8c95-7fe97faafddd md""" ## Influence des paramètres sur nos résultats """ # ╔═╡ 7cdf9477-d2a6-4846-9f4d-7f1df14f3c58 md""" ### Expert bourré Si notre expert ne va pas très bien, s'il est bourré, ou juste nul, il se peut que son échantillonnage des classes soit mauvais. ![50%](content/TP4/expert_BWbad.png) Dans ce cas comme on peut s'en douter notre vraisemblance est horrible. ![50%](content/TP4/exo1mvbad.png) Le recuit peut tout de même améliorer cet échantillonnage, mais cette segmentation reste mauvaise. ![50%](content/TP4/exo1bad.webp) """ # ╔═╡ 49747114-1019-4478-984a-759887bd9b72 md""" ### Beta recuit simulé Dans notre algorithme du recuit simulé, nous utilisons un paramètre $\beta$ représentant l'importance de notre régularisation lors d'une itération. Ainsi pour différentes valeurs de beta: """ # ╔═╡ 9607de34-a8a6-4be3-b603-bf2a20e73fde html"""
0.2 1 20
""" # ╔═╡ ca1d1182-f77b-4510-89be-e286818c41f3 md""" On observe ainsi que plus $\beta$ est élevé, moins une itération pourra apporter de bruits. Cela permet de converger plus rapidement vers notre segmentation, mais celle-ci sera un peu moins précise. """ # ╔═╡ dc971adc-b6bc-4853-afde-a163e28ebbd3 md""" ### Alpha recuit simulé Dans le recuit simulé $\alpha$ traduit quant à lui l'allure à laquelle la température décroît (selon une loi géométrique) : """ # ╔═╡ 9faecaf8-9a6a-41b4-a7e0-a9a65f039825 html"""
0.5 0.99 1.1
""" # ╔═╡ 1a381029-c50a-4631-8982-e9d90543ad44 md""" On observe que plus la température diminue, moins notre estimation aura de chance de faire réapparaitre du bruit. Ainsi un petit $\alpha$ aura tendance à geler rapidement notre figure. Un alpha proche de 1 permet globalement d'obtenir de meilleurs résultats, car une haute température corrige les petits défauts de l'estimation lors des dernières itérations. Un alpha supérieur à 1 part en couille. """ # ╔═╡ 57f39905-d77f-43f9-ab8a-c8941393498a md""" ### N non supervisé Lors d'une approche non supervisé il nous faut tout de même annoncer le nombre de classes de l'image, cette méthode fonctionne plutôt bien, mais des résultats intéressants apparaissent si l'on se trompe. """ # ╔═╡ 45b844b0-0b5e-433f-9590-70b001dceff2 html"""
2 4 8
""" # ╔═╡ e328d40b-3ba4-4fc7-b52d-aafd62f589f2 md""" On observe que plus l'on augmente le nombre de classes (dans notre cas), plus l'histogramme trouvé par MAP est précis, mais plus notre segmentation sera bruitée. L'estimation convergera tout de même (souvent) vers 4 classes, bien que nous en ayons spécifié plus. """ # ╔═╡ 709a5e59-545d-4b39-8b82-0c9fd2232d3b md""" # TP5 - Flamants roses Notre objectif dans ce TP est de procéder à la détection d'objets dans une image, plus précisément au dénombrement de flamants roses dans une image (via des cercles/ellipses roses). """ # ╔═╡ eaedfd74-c98f-4f8f-b311-09b49839f16a html""" Voici à gauche des flamants roses pour référence et à droite l'image des flamants roses que nous souhaitons dénombrer:
Je vous laisse faire le jeu des sept différences parce que je n'en vois pas. """ # ╔═╡ 8d896695-50eb-4b66-a60c-10ea12cf2417 md""" ## Dénombrement naif Une première méthode consiste à tirer à chaque itération un nouveau cercle tel que le niveau de gris moyen des pixels contenus dans l'ensemble des cercles de notre dénombrement soit plus élevé (puisque nos flamants roses sont blancs dans notre image en dégradé de gris). Voici le résultat de 1000 itérations: ![](content/TP5/exercice0.webp) On observe très clairement un problème, les flamants roses défient les lois de la physique et occupent le même espace. """ # ╔═╡ da89e6ff-5d19-48df-9106-140619914220 md""" ## Dénombrement moins con Il est donc important de rajouter la contrainte empêchant deux flamants roses (deux cercles) d'être trop près. Nous pouvons donc écrire: $\forall i \neq j, ||C_i - C_j|| \geq \sqrt2 R$ On obtient ainsi un résultat plus cohérent. ![](content/TP5/exercice1.webp) """ # ╔═╡ b133aaf9-9943-4ef7-a7ce-11daea4a3692 md""" ## Dénombrement automatique Jusqu'à maintenant notre dénombrement/détection nécessitait l'entrée $N$ (plutôt inutile sachant que c'est ce que l'on cherche). Nous pouvons déterminer le véritable nombre de flamants en utilisant un algorithme de naissance et de mort combiné à un recuit simulé. Après environ 400 itérations, on converge vers un résultat satisfaisant. ![](content/TP5/exercice2.webp) On observe bien que l'énergie globale de notre recuit diminue au cours du temps, et que le nombre de flamants $N$ converge vers ~150. """ # ╔═╡ 797f62e6-c573-4edc-90eb-c258592e299a md""" ## Dénombrement avec des ellipses Comme vous l'avez peut-être remarqué, un flamant rose ressemble peu à un cercle parfait. C'est pourquoi il est plus judicieux de modéliser les flamants roses dans notre image par des ellipses lors de notre dénombrement. Voici le résultat que l'on obtient: ![](content/TP5/exercice3.webp) On observe globalement que les ellipses collent mieux aux taches blanches de l'image, cependant puisqu'une ellipse comporte bien plus de paramètres qu'un cercle, le nombre d'itérations pour obtenir un résultat satisfaisant est bien plus grand. """ # ╔═╡ c037620f-6644-40da-a045-2a68ae2464a0 md""" # TP6 - Restauration d’images Nous souhaitons dans cette nouvelle partie restaurer des images bruitées ou abimées. """ # ╔═╡ ee234a83-5f87-42c5-85d2-9a8a609a132c md""" ## Débruitage par variation quadratique Si l'on souhaite enlever le bruit (~poivre/sel) de cette image, une première approche consiste à chercher l'application $u$ qui minimise le problème suivant: $$\text{argmin}\ E_{\text{Tikhonov}}(u) = \frac12 \iint_\Omega \left\{ \left[ u(x,y) - u_0(x,y) \right] ^2 + \lambda |\nabla u(x,y)|^2 \right\} \ dx \ dy$$ Résoudre ce problème revient à trouver une application qui transforme notre image en une image proche de celle original, mais dont le gradient serait inférieur. On obtient alors une image un peu floue. """ # ╔═╡ e90f4ee5-d0dc-4a43-a6ae-471c65f880fe html"""
bruité débruité
""" # ╔═╡ 3a5533f2-881a-4b99-96e4-4ce4bd640aec md""" ## Débruitage par variation totale Une méthode un peu plus avancée consite à résoudre le problème d'optimisation suivant: $$\text{argmin}\ E_{\text{TV}}(u) = \iint_\Omega \left\{ \frac12 \left[ u(x,y) - u_0(x,y) \right] ^2 + \lambda\sqrt{|\nabla u(x,y)|^2 + \epsilon} \right\} \ dx \ dy$$ On remplace simplement la régularisation quadratique $$\frac12 \iint_\Omega|\nabla u|^2$$ par une estimation de la régularisation totale $$\iint_\Omega|\nabla u| \simeq \iint_\Omega \sqrt{|\nabla u(x,y)|^2 + \epsilon}$$ Sur nos images précédentes on obtient alors: """ # ╔═╡ fdfb04a5-3bf1-4a71-8433-1221e8fbcce4 html"""
bruité débruitage
""" # ╔═╡ a4826006-73e0-4b15-9813-0ab5cabf25ff md""" On observe globalement toujours un lissage sur nos images, mais les contours sont cette fois bien mieux conservés. """ # ╔═╡ 2e2847a7-d102-46dc-b6cf-3767354ec003 md""" ## Inpainting par variation totale On peut résoudre le même type de problème pour restaurer une image comportant un défaut: $$\text{argmin}\ E_{Inpainting}(u) = \frac12 \iint_{\Omega \backslash \text{D}} \left[ u(x,y) - u_0(x,y) \right] ^2 \ dx \ dy + \lambda \iint_\Omega \sqrt{|\nabla u(x,y)|^2 + \epsilon} \ dx \ dy$$ """ # ╔═╡ ecdf5365-32b2-470e-bfa4-4ade78683841 html"""
bruité débruitage
original buité débruité
""" # ╔═╡ 1daa22b9-335f-436d-bf4d-053637374978 md""" ## Inpainting par rapiéçage TODO """ # ╔═╡ 28a84673-b849-4ccb-a488-9db4fe1818f6 md""" # TP7 - Techniques de photomontage L'objectif de ce TP est de permettre l'incrustation d'objets dans une scène le plus naturellement possible. """ # ╔═╡ 3a7e6fd6-9e54-41a0-90e3-a5d047e7e3de md""" ## Photomontage par collage """ # ╔═╡ 4a66976a-9f51-4bfa-971b-2d922134f196 html""" On souhaite obtenir ce type de résultats:
Image cible Image source Résultat
Dans l'exemple ci-dessus, notre source a simplement été collée sur la cible, on remarque immédiatement que ce collage est très brut, une méthode pour rendre le résultat plus plaisant est alors de faire en sorte que les gradients de la cible et de la source correspondent mieux. On obtient alors:
Image cible Image source Résultat
""" # ╔═╡ 32d4e51b-8599-4d93-905a-cb4a719710d3 md""" ## Décoloration partielle d’une image """ # ╔═╡ 7db8d120-6c7e-4394-9336-9f66de7039be html""" Un résultat intéressant que l'on peut obtenir est la décoloration partielle d'une image, en effet si l'on vient coller (via la même technique que précédemment) un morceau de l'image sur la même image en niveau de gris, on obtient alors un effet artistique:
""" # ╔═╡ 6c2d038e-b1cf-49d1-8e7e-da9d883b8c35 md""" ## Autres techniques de photomontage TODO """ # ╔═╡ 2f7ad872-4215-4d84-a30d-d3486979dd32 md""" # TP8 - Décomposition d’une image """ # ╔═╡ f77b33d9-57a1-4659-9a68-b89184838653 md""" ## Transformation de Fourier discrète 2D La transformée de fourier d'une image 2D permet d'obtenir son spectre. Comme la transformée est inversible, la transformée inverse d'un spectre permet d'obtenir une image. Ainsi si l'on modifie le spectre d'une image, on observe des changements "fréquentiels" dans celle-ci: """ # ╔═╡ aab70bb0-5328-4044-a16a-4291c1583c9b html"""
Isolation des lignes horizontales
Isolation des lignes verticales
Isolation des lignes diagonales
""" # ╔═╡ c00837b6-cd15-479e-96cb-065aa4411283 md""" ## Décomposition structure + texture Cette décomposition permet d'obtenir la structure correspond plutôt aux basses fréquences d'une image, et la texture correspond plutôt aux hautes fréquences de l'image. """ # ╔═╡ 5029374a-16c2-47aa-a057-84fcfc0e6c64 md""" ### Modèle filtre Une première méthode pour obtenir une telle décomposition est d'appliquer un filtre passe bas et un filtre passe haut au spectre de notre image : """ # ╔═╡ 646d190f-b362-42a1-85ca-d7ba7c1c63ef html"""
""" # ╔═╡ 893b847a-b149-4059-ab12-2536bc86c1b6 md""" On observe bien que la structure contient les couleurs de notre image et que la texture contient les contours de l'image. Cependant ce modèle n'est pas très précis. Pour améliorer cette décomposition, au lieu de faire un filtrage passe-bas abrupt du spectre, on peut pondérer le spectre initial par les coefficients suivants: $$\displaystyle \phi(f_x, f_y) = \frac{1}{1 + \displaystyle\frac{f_x^2 + f_y^2}{\eta}}, \quad \eta \approx 0.05$$ """ # ╔═╡ d6987fe4-d170-4be0-9f71-8956a6eddcea begin plotly() local x=range(-1, 1, step=0.01) local y=range(-1, 1, step=0.01) local eta = 0.05 local f(x,y) = 1 / ( 1 + (x^2 + y^2) / eta) plot(x, y, f, st=:surface) xlabel!("fx") ylabel!("fy") end # ╔═╡ a6157e42-aa4b-4293-acf2-83dba61bd87a md""" On obtient alors un passe-bas bien plus lisse, et par la même occasion de bien meilleurs résultats: """ # ╔═╡ f0c2aaa2-dc18-42a1-be07-5fac922e82d9 html"""
""" # ╔═╡ 1ecdda8a-d979-47b1-8e31-1511bd711302 md""" On observe cette fois-ci de bien meilleurs résultats. """ # ╔═╡ ae597ea1-5e3c-45c2-8a5a-808abf4b8a69 md""" ### Modèle ROF Une seconde approche consiste à décomposer le spectre par une méthode variationnelle (variation totale). Tout comme dans le TP6, on cherche l'image structure telle que celle-ci soit proche de l'aimge originale, mais que ses gradients soient minimisés. La texture est trouvée par complémentarité. Voici les résultats après 20 itérations : """ # ╔═╡ 9da8dadd-e786-4376-9d99-8b98ab44c24c html"""
""" # ╔═╡ c475163f-fc56-424f-aa63-4cce2b7b1a91 md""" ### Modèle TV-Hilbert Cette dernière méthode (itérative) est basiquement une amélioration de la méthode ROF, puisqu'elle contraint cette fois-ci les spectres de u et ū à être égaux dans les basses fréquences. Voici la progression de cette algorithme sur 1000 itérations: """ # ╔═╡ 6c6ff49d-569e-4998-add9-c23051713318 html"""
""" # ╔═╡ 299b92f6-8f13-4a51-b831-22f05bcc312d md""" # TP9 - Tomographie L'objectif de ce TP est d'effectuer la transformée inverse d'un sinogramme pour obtenir une image. Un sinogramme est traditionnellement obtenu à l'issue d'un CT scan: """ # ╔═╡ 1eefc8b3-d3f4-4e6f-a93d-5f4ab6bab40c html"""
""" # ╔═╡ 39cea09d-5088-475b-bd09-19e6671752c8 md""" ## Résolution algébrique Une première méthode consiste à récupérer l'information des pixels de l'image en résolvant un système linéaire. On cherche l'image $f$, et l'on connaît les données du détecteur $p$ ainsi que les pixels touchés par chaque rayon X. Le problème se visualise comme ceci : """ # ╔═╡ 95a9918a-7223-4f69-98f0-c70425db2355 md""" $(Resource("https://www.researchgate.net/profile/Omid-Ghasemalizadeh-2/publication/267810464/figure/fig1/AS:392051561648154@1470483784811/Area-integral-model-of-algebraic-reconstruction-technique-ART-in-the-fan-beam-geometry.png")) """ # ╔═╡ e82a9905-eb01-43b6-bf2d-050548f33df9 md""" Si l'on note $W$ la matrice contenant la longueur du trajet d'un rayon X par rapport à chaque pixel de l'image, on peut construite le système: $$W f = p$$ Comme $W$ est de grande taille on utilise [l'algorithme itératif de Kaczmarz](https://en.wikipedia.org/wiki/Kaczmarz_method) pour résoudre le système. Voici donc les résultats d'une dizaine d'itérations sur plusieurs images: """ # ╔═╡ c8448dfc-1b07-43f0-9728-252a90bbba51 html"""
Image originale Sinogramme Image reconstituée
""" # ╔═╡ c7f093d9-5a8a-4c18-ac65-f1b03673a14d md""" ## Résolution par rétroprojection Une seconde méthode méthode plus rapide revient à "étaler" chaque échantillon du capteur (donc une tranche/colonne de notre sinogramme) sur la grille de pixel. $(Resource("https://www.dspguide.com/graphics/F_25_16.gif")) Les résultats que l'on obtient sont plutôt convaincant: """ # ╔═╡ 300fdf66-84d8-4ca0-b84e-af1deb3945ac html"""
""" # ╔═╡ e0f2cb2c-4b7b-4a24-b0a0-50db401d963e md""" ## Résolution par utilisation du théorème du profil central TODO """ # ╔═╡ f1dc867a-5683-4218-9723-25fb98d92875 md""" # TP10 – Compression audio L'objectif de ce TP est de manipuler des fichiers audio via leurs spectrogrammes, notamment pour faire de la compression. """ # ╔═╡ 9797d171-bc06-4697-9ead-4a18b4327f49 md""" ## [Spectrogramme](https://en.wikipedia.org/wiki/Spectrogram) Pour construire le spectrogramme de notre audio, nous allons effectuer la transformée de fourrier sur des morceaux successifs du signal (avec overlapping ou non). Nous pouvons de même choisir une [fenêtre](https://en.wikipedia.org/wiki/Window_function), pour pondérer nos échantillons lors de la transformée de fourrier, celle-ci influe sur le [_spectral leakage_](https://en.wikipedia.org/wiki/Spectral_leakage). Il existe bon nombre de fenêtres : """ # ╔═╡ f037c06f-db56-4c46-9fa1-88c52e6943b9 begin local n = 100 plotly() plot(DSP.rect(n), label="rectangle") plot!(DSP.hanning(n), label="hanning") plot!(DSP.hamming(n), label="hamming", visible="legendonly") plot!(DSP.tukey(n, 0.5), label="tukey", visible="legendonly") plot!(DSP.cosine(n), label="cosine", visible="legendonly") plot!(DSP.lanczos(n), label="lanczos", visible="legendonly") plot!(DSP.triang(n), label="triang", visible="legendonly") plot!(DSP.bartlett(n), label="bartlett", visible="legendonly") plot!(DSP.gaussian(n, 0.15), label="gaussian", visible="legendonly") plot!(DSP.blackman(n), label="blackman", visible="legendonly") plot!(DSP.kaiser(n, 10), label="kaiser", visible="legendonly") end # ╔═╡ e7c84285-20ef-44b6-82af-52ccc6e98163 md""" Pour le calcul de nos spectrogrammes nous choisiront la fenêtre de Hanning. Voici donc les spectrogrammes de plusieurs audios: """ # ╔═╡ dca00dac-cccd-448a-a4a2-2a38b981d2e7 html"""
Audio Spectrogramme
007
Beethoven
Grapelli
Mourousi
""" # ╔═╡ 7439ea28-5e00-4a5a-ad0c-6b23771df9ea md""" ## Compression acoustique Une des premières problématiques de l'audio numérique est la compression (bien que moins prévalente aujourd'hui). """ # ╔═╡ ae215d41-addb-4694-867c-4720cd6835a1 md""" ### Tronquage Une première méthode, très simple, est de tronquer le spectrogramme de notre audio au-delà d'une certaine fréquence. """ # ╔═╡ 494bedcf-1e3a-44d6-a51f-8c29cfb50830 html"""
Audio Spectrogramme
007
Beethoven
Grapelli
Mourousi
""" # ╔═╡ d12f3d01-ed74-4204-82e6-19f43e559699 md""" Puisque nos audio comportent peu d'informations dans les hautes fréquences, cela les impacte peu. De même, les amplitudes des coefficients de Fourrier dans les hautes fréquences étant faibles, leur disparition est difficilement remarquable. """ # ╔═╡ f769a263-d8df-4b40-9de7-3d6517095557 md""" ### MP3 Pour compresser plus fortement notre signal nous pouvons reprendre une des idées sur célèbre format de compression [MP3](https://en.wikipedia.org/wiki/MP3). Cette idée consiste à garder sur chaque tranche temporelle les $n$ coeffcients de Fourrier les plus élevés. Pour $n=100$ on observe alors une compression très forte (~10% de la taille initiale), et pourtant l'audio original est toujours distinguable. Pour des $n$ plus élevés, il devient possible d'obtenir une [transparence](https://en.wikipedia.org/wiki/Transparency_(data_compression)) de l'audio, tout en réduisant la taille du fichier. """ # ╔═╡ 247bf9c5-4f0a-4ed2-a604-1e9ef8b64b01 html"""
Audio Spectrogramme
007
Beethoven
Grapelli
Mourousi
""" # ╔═╡ 9c95a7a3-bd09-4a69-a5b2-ec39f4e3d868 md""" ## Stéganographie TODO """ # ╔═╡ d33bd7b5-904b-4fbf-964e-5f32a34d26a6 md""" ## Débruitage Une dernière application du spectrogramme est le débruitage. Voyons ici une méthode plutôt simple appelée le [_spectral noise gating_](https://wiki.audacityteam.org/wiki/How_Audacity_Noise_Reduction_Works) notamment implémentée dans le fameux logiciel [Audacity](https://en.wikipedia.org/wiki/Audacity_(audio_editor)). Cette technique nécessite un extrait audio avec uniquement le bruit (isolé) que l'on souhaite supprimer. Nous pouvons effectuer sur cet extrait une estimation d'une loi normale. À partir de cette estimation, nous définissons un seuil, qui nous permettra par la suite d'atténuer sur notre véritable audio le bruit. """ # ╔═╡ 109586dd-7ff7-4d09-981c-173775a0debb html"""
Audio bruité Audio débruité
007
 
Beethoven
 
Grapelli
 
Mourousi
 
""" # ╔═╡ 2afd14dd-78e5-4205-93df-c5020ab3253f md""" # TP11 - Shazam L'objectif de ce TP est de trouver des points remarquables dans des enregistrements sonores, pour permettre leur identification. """ # ╔═╡ 13f60f6b-3bac-4ba7-9ae6-233fac4bbfdd md""" ## Calcul des pics spectraux Une méthode assez simple consiste alors à trouver les maximums locaux du spectrogramme de l'audio. """ # ╔═╡ bd53b23f-9aaf-4fce-af04-0b8592d646be html"""
Aimee Mann-Wise Up
Altın Gün-Süpürgesi Yoncadan
Gultrah Sound System-Elli tchelou
Nina Simone-My Baby Just Cares For Me
""" # ╔═╡ f6625979-61d8-4e17-b4fa-0c673c53edea md""" Ces maximas permettent de plutôt bien de caractériser les audios. Cependant on peut faire mieux. """ # ╔═╡ b7254213-a06b-45c7-a1cb-e799a0cc4844 md""" ## Appariement des pics spectraux Une amélioration consiste à relier les les pics proches de manière à former des couples de maximas. """ # ╔═╡ 4b54f396-a3a6-4fde-bf1c-11b8c4579c21 html"""
Aimee Mann-Wise Up
Altın Gün-Süpürgesi Yoncadan
Gultrah Sound System-Elli tchelou
Nina Simone-My Baby Just Cares For Me
""" # ╔═╡ 2ae06afc-1cb2-485a-8b05-e9c76b7aa4e4 md""" Cette méthode est bien meilleure puisqu'elle permet de rejeter bien plus rapidement les audios qui partagent des maximas avec le son recherché mais qui ne correspondent pas parfaitement. """ # ╔═╡ f4f00c5d-7bad-4261-a683-ef374ccde1d8 md""" ### Indexation des paires de pics spectraux Pour consistuer la base de données avec laquelle nous allons reconnaitre des extraits audio. Nous pouvons créer une hasmap entre les paires de maximas et les sons correspondants. Pour simplifier la représentation des couples, nous allons les encoder dans un entier non signé de 32 bits: """ # ╔═╡ 5399561a-f4d1-465f-88da-9452746625b8 md""" | (ti, tj, fi, fj) | (ti, tj, fj - fi) | uint32 | | :------------------: | :---------------: | :--------: | | (1, 2, 3, 4) | (1, 2, 1) | 0x00010001 | | (10, 20, 30, 40) | (10, 20, 10) | 0x0913000a | | (100, 200, 300, 400) | (100, 200, 100) | 0x63c70064 | | ⋮ | ⋮ | ⋮ | """ # ╔═╡ 6256ef07-6188-41fe-bddc-c006cba557bd md""" ## Reconnaissance musicale Nous pouvons désormais tester notre algorithme en lui fournissant des courts extraits sonores, dont la musique complète est dans notre base de données. """ # ╔═╡ 14f43c7e-fdb1-4bc5-8820-dcc90ebff3b7 md""" ### Reconnaissance simplifié En calculant les paires de maximas dans le spectrogramme de l'extrait et en trouvant la musique dont les paires correspondent le plus dans notre base de données, on peut alors faire une prédiction. Cet algorithme reconnait bien les 4 musiques vues plus haut: - 2 - Aimee Mann-Wise Up - 4 - Altın Gün-Süpürgesi Yoncadan - 42 - Gultrah Sound System-Elli tchelou - 69 - Nina Simone-My Baby Just Cares For Me De manière générale, sur l'ensemble des musiques de notre base de données, cet algorithme effectue 90% du temps une bonne prédiction. """ # ╔═╡ 49c73149-e31a-41f0-8857-7d4a035e098f md""" ### Reconnaissance avancée Une méthode pour améliorer nos résultats est de prendre en compte la cohérence entre les instants d’apparition des paires de pics de l’extrait et ceux du morceau présent dans la base de données. Pour réaliser cela on peut simplement stocker une approximation du début de l'extrait audio dans l'audio intégrale. En prenant le temps de plus commun ($t_0$) et en filtrant tous nos résultats tels que: $t_0 \leq t \leq t_0 + t_{echantillon}$. On obtient un algorithme d'une précision presque parfaite. """ # ╔═╡ 9b4befdd-8ed9-4269-9a7e-0e8afc10eaa9 md""" # TP12 - Séparation de sources L'objectif de ce TP est de retrouver les "pistes audio d'un mélange", à partir de l'audio final. """ # ╔═╡ abf219da-d9bf-410f-9c3f-14ddbd5fbb34 md""" ## Décomposition harmonique/percussive """ # ╔═╡ 8cebf3fb-1db5-42b7-9214-b53e8607bff2 md""" - Un son harmonique varie peu au cours du temps, son sonagramme fait apparaître des lignes horizontales. - Un son percussif est bref mais très riche en fréquences, son sonagramme fait apparaître des lignes verticales. """ # ╔═╡ 435410b9-d7c5-4aba-989c-58ffbbd93c6e html"""
Harmoniques (violon) Percussions (batterie)
""" # ╔═╡ 54bd596e-4d22-4894-b2e0-63f424f3a540 md""" On cherche alors à séparer dans un audio les harmoniques et les percussions, soit les traits verticaux et horizontaux sur le spectrogramme. """ # ╔═╡ 232c1de0-5ec4-4c64-904c-4bc9acd098df html"""
Audio Spectrogramme
violon + batterie
""" # ╔═╡ 2d5c6ac0-4eed-4f2e-8600-42e605a47f22 md""" En appliquant un filtre médian "horizontal" de taille (n, 1) sur notre spectrogramme, somme capable de créer un masque représentant les lignes horizontales du spectrogramme. De même avec un filtre médian "vertical" de taille (n, 1), on extrait les lignes verticales du spectrogramme: """ # ╔═╡ ca95bbed-d34a-4d15-980a-d3aeaf2bbada html"""
Masque harmoniques Masque percussions
""" # ╔═╡ 0a850a9e-6c57-4d8f-9d60-07113b004967 md""" Si l'on applique ainsi ces masques à notre spectrogramme, on obtient alors un résultat correct: """ # ╔═╡ a5e5700a-0c01-47b5-ae00-0bdc86cacc4e html"""
Harmoniques Percussions
""" # ╔═╡ 7a39222f-6155-41c6-a1fe-66ecc42203b8 md""" ## Décomposition NMF La factorisation en matrices non négatives (NMF, pour Non-negative Matrix Factorization) consiste à approximer une matrice $S$ à coefficients non négatifs (notre spectrogramme ici), par le produit de deux matrices $D$ et $A$ à coefficients non négatifs de rang $R$. On souhaite avec cette technique décompose un audio en $R$ piste distinctes. Numériquement cette décomposition revient à appliquer itérativement les opérations suivantes: $$A^{(k+1)} = A^{(k)} \odot (D^\top S) \oslash (D^\top D A^{(k)})$$ $$D^{(k+1)} = D^{(k)} \odot (S A^\top) \oslash (D^{(k)} A A^\top)$$ avec $S \in M_{n, m}(R_+)$, $D^{(0)} \in M_{n, R}(R_+)$, $A^{(0)} \in M_{R, m}(R_+)$. Voici le résultat d'une trentaine d'itération pour $R = 4$: """ # ╔═╡ 740501ba-2e31-4ff4-968e-1dfb33cbbe78 html"""
""" # ╔═╡ 2a93b54d-4d97-4850-83df-47f0902fc72f md""" Nous pouvons de même extraire chacune des composantes, les écouter et intuiter leur utilité: """ # ╔═╡ 57c14c36-e5c6-4049-ba2d-79e5825533b1 html"""
Audio Spectrogramme
Composante n°1
Composante n°2
Composante n°3
Composante n°4
""" # ╔═╡ 635832fe-1b8c-40c0-9b94-968f449c89e6 md""" ### Variation de R Il est intéressant de faire varier $R$ pour observer son effet sur le résultat final. """ # ╔═╡ 7bb25bbc-f4b4-41d6-bd4b-17df602d0fd5 md""" #### R = 1 Pour un rang faible, on remarque que chaque "note" aura tendance à contenir plusieurs véritable notes. """ # ╔═╡ e6038ed1-95d1-4241-99d4-5789b0715981 html"""
""" # ╔═╡ dd6e50f2-d3d9-4810-a064-8404f9189f7a md""" #### R = 25 Pour un rang élevé, on remarque que chaque "note" aura tendance à n'être que des morceaux de notes. """ # ╔═╡ d92d7f39-7e4b-40b8-93a3-118c2ea03db5 html"""
""" # ╔═╡ be37333b-4350-4405-9f2f-80b3a5f566a7 md""" On conclut alors qu'il faut choisir minutieusement $R$. """ # ╔═╡ 1c38a45b-d50f-48f6-831e-d3b4b2fe9641 md""" ## Décomposition par dictionnaire """ # ╔═╡ 0909842d-2a28-4c11-92dd-e95acd070c41 md""" Pour obtenir de meilleurs résultats nous pouvons initialiser les matrices $D$ et $A$ à partir de notes existantes. De cette manière nous devrions converger vers des minimas plus proches, et les itérations serviront uniquement à affiner les notes initiales pour que celles-ci collent mieux à notre audio. """ # ╔═╡ 602994bf-c91d-4f39-8286-405d4bcede38 html"""
""" # ╔═╡ 80b2e36a-5464-454a-a5cd-6980e89aa5b7 md""" Un cas d'application de cette initialisation est de permettre la séparation de sources. En effet si nous initialisons nos matrices à partir de notes de piano et de violons, en coupant en deux nos matrices A et D finales nous sommes maintenant capable de séparer l'audio du violon et du piano. """ # ╔═╡ af94b4a6-94bc-4a8e-956a-488c050a7b20 html"""
""" # ╔═╡ 7f3da391-00db-4d83-a617-044503b92acf md""" ## Classification des notes du dictionnaire TODO """ # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MAT = "23992714-dd62-5051-b70f-ba57cb901cac" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" [compat] DSP = "~0.7.5" Distributions = "~0.25.48" MAT = "~0.10.3" Plots = "~1.28.1" PlutoUI = "~0.7.34" StatsPlots = "~0.14.33" """ # ╔═╡ 00000000-0000-0000-0000-000000000002 PLUTO_MANIFEST_TOML_CONTENTS = """ # This file is machine-generated - editing it directly is not advised julia_version = "1.9.1" manifest_format = "2.0" project_hash = "09ba23f9feefa3ab0528920701e07c04901f9ef3" [[deps.AbstractFFTs]] deps = ["LinearAlgebra"] git-tree-sha1 = "8bc0aaec0ca548eb6cf5f0d7d16351650c1ee956" uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" version = "1.3.2" weakdeps = ["ChainRulesCore"] [deps.AbstractFFTs.extensions] AbstractFFTsChainRulesCoreExt = "ChainRulesCore" [[deps.AbstractPlutoDingetjes]] deps = ["Pkg"] git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" uuid = "6e696c72-6542-2067-7265-42206c756150" version = "1.1.4" [[deps.Adapt]] deps = ["LinearAlgebra", "Requires"] git-tree-sha1 = "76289dc51920fdc6e0013c872ba9551d54961c24" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" version = "3.6.2" weakdeps = ["StaticArrays"] [deps.Adapt.extensions] AdaptStaticArraysExt = "StaticArrays" [[deps.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.1" [[deps.Arpack]] deps = ["Arpack_jll", "Libdl", "LinearAlgebra", "Logging"] git-tree-sha1 = "9b9b347613394885fd1c8c7729bfc60528faa436" uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" version = "0.5.4" [[deps.Arpack_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg"] git-tree-sha1 = "5ba6c757e8feccf03a1554dfaf3e26b3cfc7fd5e" uuid = "68821587-b530-5797-8361-c406ea357684" version = "3.5.1+1" [[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [[deps.AxisAlgorithms]] deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" version = "1.0.1" [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[deps.BufferedStreams]] git-tree-sha1 = "5bcb75a2979e40b29eb250cb26daab67aa8f97f5" uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d" version = "1.2.0" [[deps.Bzip2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" version = "1.0.8+0" [[deps.Cairo_jll]] deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_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 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" version = "1.16.1+1" [[deps.Calculus]] deps = ["LinearAlgebra"] git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" version = "0.5.1" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] git-tree-sha1 = "e30f2f4e20f7f186dc36529910beaedc60cfa644" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" version = "1.16.0" [[deps.Clustering]] deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "Random", "SparseArrays", "Statistics", "StatsBase"] git-tree-sha1 = "7ebbd653f74504447f1c33b91cd706a69a1b189f" uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5" version = "0.14.4" [[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] git-tree-sha1 = "9c209fb7536406834aa938fb149964b985de6c83" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" version = "0.7.1" [[deps.ColorSchemes]] deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] git-tree-sha1 = "be6ab11021cd29f0344d5c4357b163af05a48cba" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" version = "3.21.0" [[deps.ColorTypes]] deps = ["FixedPointNumbers", "Random"] git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" version = "0.11.4" [[deps.ColorVectorSpace]] deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] git-tree-sha1 = "600cc5508d66b78aae350f7accdb58763ac18589" uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" version = "0.9.10" [[deps.Colors]] deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a" uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" version = "0.12.10" [[deps.Compat]] deps = ["UUIDs"] git-tree-sha1 = "4e88377ae7ebeaf29a047aa1ee40826e0b708a5d" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" version = "4.7.0" weakdeps = ["Dates", "LinearAlgebra"] [deps.Compat.extensions] CompatLinearAlgebraExt = "LinearAlgebra" [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" version = "1.0.2+0" [[deps.Contour]] deps = ["StaticArrays"] git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" version = "0.5.7" [[deps.DSP]] deps = ["Compat", "FFTW", "IterTools", "LinearAlgebra", "Polynomials", "Random", "Reexport", "SpecialFunctions", "Statistics"] git-tree-sha1 = "da8b06f89fce9996443010ef92572b193f8dca1f" uuid = "717857b8-e6f2-59f4-9121-6e50c889abd2" version = "0.7.8" [[deps.DataAPI]] git-tree-sha1 = "8da84edb865b0b5b0100c0666a9bc9a0b71c553c" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" version = "1.15.0" [[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] git-tree-sha1 = "cf25ccb972fec4e4817764d01c82386ae94f77b4" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" version = "0.18.14" [[deps.DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" version = "1.0.0" [[deps.DataValues]] deps = ["DataValueInterfaces", "Dates"] git-tree-sha1 = "d88a19299eba280a6d062e135a43f00323ae70bf" uuid = "e7dc6d0d-1eca-5fa6-8ad6-5aecde8b7ea5" version = "0.4.13" [[deps.Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DelimitedFiles]] deps = ["Mmap"] git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" version = "1.9.1" [[deps.Distances]] deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"] git-tree-sha1 = "49eba9ad9f7ead780bfb7ee319f962c811c6d3b2" uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" version = "0.10.8" [[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" [[deps.Distributions]] deps = ["FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "Test"] git-tree-sha1 = "db40d3aff76ea6a3619fdd15a8c78299221a2394" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" version = "0.25.97" [deps.Distributions.extensions] DistributionsChainRulesCoreExt = "ChainRulesCore" DistributionsDensityInterfaceExt = "DensityInterface" [deps.Distributions.weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" [[deps.DocStringExtensions]] deps = ["LibGit2"] git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" version = "0.9.3" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" version = "1.6.0" [[deps.DualNumbers]] deps = ["Calculus", "NaNMath", "SpecialFunctions"] git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" version = "0.6.8" [[deps.EarCut_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" version = "2.2.4+0" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "4558ab818dcceaab612d1bb8c19cee87eda2b83c" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" version = "2.5.0+0" [[deps.Extents]] git-tree-sha1 = "5e1e4c53fa39afe63a7d356e30452249365fba99" uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" version = "0.1.1" [[deps.FFMPEG]] deps = ["FFMPEG_jll"] git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" version = "0.4.1" [[deps.FFMPEG_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" version = "4.4.2+2" [[deps.FFTW]] deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] git-tree-sha1 = "b4fbdd20c889804969571cc589900803edda16b7" uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" version = "1.7.1" [[deps.FFTW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" version = "3.3.10+0" [[deps.FileWatching]] uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" [[deps.FillArrays]] deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] git-tree-sha1 = "0b3b52afd0f87b0a3f5ada0466352d125c9db458" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" version = "1.2.1" [[deps.FixedPointNumbers]] deps = ["Statistics"] git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" version = "0.8.4" [[deps.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" [[deps.Formatting]] deps = ["Printf"] git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" version = "0.4.2" [[deps.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" [[deps.FriBidi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" uuid = "559328eb-81f9-559d-9380-de523a88c83c" version = "1.0.10+0" [[deps.GLFW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] git-tree-sha1 = "d972031d28c8c8d9d7b41a536ad7bb0c2579caca" uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" version = "3.3.8+0" [[deps.GPUArraysCore]] deps = ["Adapt"] git-tree-sha1 = "2d6ca471a6c7b536127afccfa7564b5b39227fe0" uuid = "46192b85-c4d5-4398-a991-12ede77f4527" version = "0.1.5" [[deps.GR]] deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"] git-tree-sha1 = "c98aea696662d09e215ef7cda5296024a9646c75" uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" version = "0.64.4" [[deps.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 = "bc9f7725571ddb4ab2c4bc74fa397c1c5ad08943" uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" version = "0.69.1+0" [[deps.GeoInterface]] deps = ["Extents"] git-tree-sha1 = "bb198ff907228523f3dee1070ceee63b9359b6ab" uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" version = "1.3.1" [[deps.GeometryBasics]] deps = ["EarCut_jll", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] git-tree-sha1 = "659140c9375afa2f685e37c1a0b9c9a60ef56b40" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" version = "0.4.7" [[deps.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" [[deps.Glib_jll]] deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Pkg", "Zlib_jll"] git-tree-sha1 = "d3b3624125c1474292d0d8ed0f65554ac37ddb23" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" version = "2.74.0+2" [[deps.Graphite2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" version = "1.3.14+0" [[deps.Grisu]] git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" version = "1.0.2" [[deps.HDF5]] deps = ["Compat", "HDF5_jll", "Libdl", "Mmap", "Random", "Requires", "UUIDs"] git-tree-sha1 = "c73fdc3d9da7700691848b78c61841274076932a" uuid = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" version = "0.16.15" [[deps.HDF5_jll]] deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenSSL_jll", "Pkg", "Zlib_jll"] git-tree-sha1 = "4cc2bb72df6ff40b055295fdef6d92955f9dede8" uuid = "0234f1f7-429e-5d53-9886-15a909be8d59" version = "1.12.2+2" [[deps.HTTP]] deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" version = "0.9.17" [[deps.HarfBuzz_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" version = "2.8.1+1" [[deps.HypergeometricFunctions]] deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] git-tree-sha1 = "0ec02c648befc2f94156eaef13b0f38106212f3f" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" version = "0.3.17" [[deps.Hyperscript]] deps = ["Test"] git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" version = "0.0.4" [[deps.HypertextLiteral]] deps = ["Tricks"] git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" version = "0.9.4" [[deps.IOCapture]] deps = ["Logging", "Random"] git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" version = "0.2.3" [[deps.IniFile]] git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625" uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" version = "0.5.1" [[deps.IntelOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "0cb9352ef2e01574eeebdb102948a58740dcaf83" uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" version = "2023.1.0+0" [[deps.InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[deps.Interpolations]] deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] git-tree-sha1 = "b7bc05649af456efc75d178846f47006c2c4c3c7" uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" version = "0.13.6" [[deps.IrrationalConstants]] git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" version = "0.2.2" [[deps.IterTools]] git-tree-sha1 = "4ced6667f9974fc5c5943fa5e2ef1ca43ea9e450" uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" version = "1.8.0" [[deps.IteratorInterfaceExtensions]] git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" [[deps.JLLWrappers]] deps = ["Preferences"] git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" version = "1.4.1" [[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.4" [[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "6f2675ef130a300a112286de91973805fcc5ffbc" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" version = "2.1.91+0" [[deps.KernelDensity]] deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] git-tree-sha1 = "90442c50e202a5cdf21a7899c66b240fdef14035" uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" version = "0.6.7" [[deps.LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" version = "3.100.1+0" [[deps.LERC_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" uuid = "88015f11-f218-50d7-93a8-a6af411a945d" version = "3.0.0+1" [[deps.LLVMOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "f689897ccbe049adb19a065c495e75f372ecd42b" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" version = "15.0.4+0" [[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" version = "2.10.1+0" [[deps.LaTeXStrings]] git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" version = "1.3.0" [[deps.Latexify]] deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Printf", "Requires"] git-tree-sha1 = "8c57307b5d9bb3be1ff2da469063628631d4d51e" uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" version = "0.15.21" [deps.Latexify.extensions] DataFramesExt = "DataFrames" DiffEqBiologicalExt = "DiffEqBiological" ParameterizedFunctionsExt = "DiffEqBase" SymEngineExt = "SymEngine" [deps.Latexify.weakdeps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DiffEqBiological = "eb300fae-53e8-50a0-950c-e21f52c2b7e0" SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" [[deps.LazyArtifacts]] deps = ["Artifacts", "Pkg"] uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.3" [[deps.LibCURL_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" version = "7.84.0+0" [[deps.LibGit2]] deps = ["Base64", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" [[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "MbedTLS_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" version = "1.10.2+0" [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" [[deps.Libffi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" version = "3.2.2+1" [[deps.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" [[deps.Libglvnd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733" uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" version = "1.6.0+0" [[deps.Libgpg_error_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" version = "1.42.0+0" [[deps.Libiconv_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "c7cb1f5d892775ba13767a87c7ada0b980ea0a71" uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" version = "1.16.1+2" [[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" version = "2.35.0+0" [[deps.Libtiff_jll]] deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] git-tree-sha1 = "3eb79b0ca5764d4799c06699573fd8f533259713" uuid = "89763e89-9b03-5906-acba-b20f662cd828" version = "4.4.0+0" [[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" version = "2.36.0+0" [[deps.LinearAlgebra]] deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[deps.LogExpFunctions]] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] git-tree-sha1 = "c3ce8e7420b3a6e071e0fe4745f5d4300e37b13f" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" version = "0.3.24" [deps.LogExpFunctions.extensions] LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" LogExpFunctionsInverseFunctionsExt = "InverseFunctions" [deps.LogExpFunctions.weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[deps.MAT]] deps = ["BufferedStreams", "CodecZlib", "HDF5", "SparseArrays"] git-tree-sha1 = "79fd0b5ee384caf8ebba6c8fb3f365ca3e2c5493" uuid = "23992714-dd62-5051-b70f-ba57cb901cac" version = "0.10.5" [[deps.MIMEs]] git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" version = "0.1.4" [[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] git-tree-sha1 = "154d7aaa82d24db6d8f7e4ffcfe596f40bff214b" uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" version = "2023.1.0+0" [[deps.MacroTools]] deps = ["Markdown", "Random"] git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" version = "0.5.10" [[deps.Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[deps.MbedTLS]] deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "Random", "Sockets"] git-tree-sha1 = "03a9b9718f5682ecb107ac9f7308991db4ce395b" uuid = "739be429-bea8-5141-9913-cc70e7f3736d" version = "1.1.7" [[deps.MbedTLS_jll]] deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" version = "2.28.2+0" [[deps.Measures]] git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" version = "0.3.2" [[deps.Missings]] deps = ["DataAPI"] git-tree-sha1 = "f66bdc5de519e8f8ae43bdc598782d35a25b1272" uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" version = "1.1.0" [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2022.10.11" [[deps.MultivariateStats]] deps = ["Arpack", "LinearAlgebra", "SparseArrays", "Statistics", "StatsBase"] git-tree-sha1 = "6d019f5a0465522bbfdd68ecfad7f86b535d6935" uuid = "6f286f6a-111f-5878-ab1e-185364afe411" version = "0.9.0" [[deps.NaNMath]] deps = ["OpenLibm_jll"] git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.0.2" [[deps.NearestNeighbors]] deps = ["Distances", "StaticArrays"] git-tree-sha1 = "2c3726ceb3388917602169bed973dbc97f1b51a8" uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" version = "0.4.13" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" [[deps.Observables]] git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d" uuid = "510215fc-4207-5dde-b226-833fc4488ee2" version = "0.4.0" [[deps.OffsetArrays]] deps = ["Adapt"] git-tree-sha1 = "82d7c9e310fe55aa54996e6f7f94674e2a38fcb4" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" version = "1.12.9" [[deps.Ogg_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" version = "0.3.21+4" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" version = "0.8.1+0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "1aa4b74f80b01c6bc2b89992b861b5f210e665b5" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" version = "1.1.21+0" [[deps.OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" version = "0.5.5+0" [[deps.Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" uuid = "91d4177d-7536-5919-b921-800302f37372" version = "1.3.2+0" [[deps.OrderedCollections]] git-tree-sha1 = "d321bf2de576bf25ec4d3e4360faca399afca282" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.6.0" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" version = "10.42.0+0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] git-tree-sha1 = "67eae2738d63117a196f497d7db789821bce61d1" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" version = "0.11.17" [[deps.Parsers]] deps = ["Dates", "PrecompileTools", "UUIDs"] git-tree-sha1 = "4b2e829ee66d4218e0cef22c0a64ee37cf258c29" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" version = "2.7.1" [[deps.Pixman_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] git-tree-sha1 = "64779bc4c9784fee475689a1752ef4d5747c5e87" uuid = "30392449-352a-5448-841d-b1acce4e97dc" version = "0.42.2+0" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" version = "1.9.0" [[deps.PlotThemes]] deps = ["PlotUtils", "Statistics"] git-tree-sha1 = "1f03a2d339f42dca4a4da149c7e15e9b896ad899" uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" version = "3.1.0" [[deps.PlotUtils]] deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"] git-tree-sha1 = "f92e1315dadf8c46561fb9396e525f7200cdc227" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" version = "1.3.5" [[deps.Plots]] deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] git-tree-sha1 = "9101f17d98edd72a44db95afcaf3534d500da058" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" version = "1.28.2" [[deps.PlutoUI]] deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] git-tree-sha1 = "b478a748be27bd2f2c73a7690da219d0844db305" uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" version = "0.7.51" [[deps.Polynomials]] deps = ["LinearAlgebra", "RecipesBase"] git-tree-sha1 = "3aa2bb4982e575acd7583f01531f241af077b163" uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" version = "3.2.13" [deps.Polynomials.extensions] PolynomialsChainRulesCoreExt = "ChainRulesCore" PolynomialsMakieCoreExt = "MakieCore" PolynomialsMutableArithmeticsExt = "MutableArithmetics" [deps.Polynomials.weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" [[deps.PrecompileTools]] deps = ["Preferences"] git-tree-sha1 = "9673d39decc5feece56ef3940e5dafba15ba0f81" uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" version = "1.1.2" [[deps.Preferences]] deps = ["TOML"] git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" uuid = "21216c6a-2e73-6563-6e65-726566657250" version = "1.4.0" [[deps.Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[deps.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 = "0c03844e2231e12fda4d0086fd7cbe4098ee8dc5" uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" version = "5.15.3+2" [[deps.QuadGK]] deps = ["DataStructures", "LinearAlgebra"] git-tree-sha1 = "6ec7ac8412e83d57e313393220879ede1740f9ee" uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" version = "2.8.2" [[deps.REPL]] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.Random]] deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[deps.Ratios]] deps = ["Requires"] git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b" uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" version = "0.4.5" weakdeps = ["FixedPointNumbers"] [deps.Ratios.extensions] RatiosFixedPointNumbersExt = "FixedPointNumbers" [[deps.RecipesBase]] deps = ["PrecompileTools"] git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" version = "1.3.4" [[deps.RecipesPipeline]] deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] git-tree-sha1 = "dc1e451e15d90347a7decc4221842a022b011714" uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" version = "0.5.2" [[deps.Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" version = "1.2.2" [[deps.RelocatableFolders]] deps = ["SHA", "Scratch"] git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca" uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" version = "0.1.3" [[deps.Requires]] deps = ["UUIDs"] git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" uuid = "ae029012-a4dd-5104-9daa-d747884805df" version = "1.3.0" [[deps.Rmath]] deps = ["Random", "Rmath_jll"] git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b" uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" version = "0.7.1" [[deps.Rmath_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "6ed52fdd3382cf21947b15e8870ac0ddbff736da" uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" version = "0.4.0+0" [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" [[deps.Scratch]] deps = ["Dates"] git-tree-sha1 = "30449ee12237627992a99d5e30ae63e4d78cd24a" uuid = "6c6a2e73-6563-6170-7368-637461726353" version = "1.2.0" [[deps.SentinelArrays]] deps = ["Dates", "Random"] git-tree-sha1 = "04bdff0b09c65ff3e06a05e3eb7b120223da3d39" uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" version = "1.4.0" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [[deps.SharedArrays]] deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" [[deps.Showoff]] deps = ["Dates", "Grisu"] git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" version = "1.0.3" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" [[deps.SortingAlgorithms]] deps = ["DataStructures"] git-tree-sha1 = "c60ec5c62180f27efea3ba2908480f8055e17cee" uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" version = "1.1.1" [[deps.SparseArrays]] deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] git-tree-sha1 = "7beb031cf8145577fbccacd94b8a8f4ce78428d3" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" version = "2.3.0" weakdeps = ["ChainRulesCore"] [deps.SpecialFunctions.extensions] SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" [[deps.StaticArrays]] deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] git-tree-sha1 = "832afbae2a45b4ae7e831f86965469a24d1d8a83" uuid = "90137ffa-7385-5640-81b9-e52037218182" version = "1.5.26" [[deps.StaticArraysCore]] git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" version = "1.4.0" [[deps.Statistics]] deps = ["LinearAlgebra", "SparseArrays"] uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" version = "1.9.0" [[deps.StatsAPI]] deps = ["LinearAlgebra"] git-tree-sha1 = "45a7769a04a3cf80da1c1c7c60caf932e6f4c9f7" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" version = "1.6.0" [[deps.StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" version = "0.33.21" [[deps.StatsFuns]] deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] git-tree-sha1 = "f625d686d5a88bcd2b15cd81f18f98186fdc0c9a" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" version = "1.3.0" [deps.StatsFuns.extensions] StatsFunsChainRulesCoreExt = "ChainRulesCore" StatsFunsInverseFunctionsExt = "InverseFunctions" [deps.StatsFuns.weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" [[deps.StatsPlots]] deps = ["AbstractFFTs", "Clustering", "DataStructures", "DataValues", "Distributions", "Interpolations", "KernelDensity", "LinearAlgebra", "MultivariateStats", "Observables", "Plots", "RecipesBase", "RecipesPipeline", "Reexport", "StatsBase", "TableOperations", "Tables", "Widgets"] git-tree-sha1 = "4d9c69d65f1b270ad092de0abe13e859b8c55cad" uuid = "f3b207a7-027a-5e70-b257-86293d7955fd" version = "0.14.33" [[deps.StructArrays]] deps = ["Adapt", "DataAPI", "GPUArraysCore", "StaticArraysCore", "Tables"] git-tree-sha1 = "521a0e828e98bb69042fec1809c1b5a680eb7389" uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" version = "0.6.15" [[deps.SuiteSparse]] deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" version = "5.10.1+6" [[deps.TOML]] deps = ["Dates"] uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" version = "1.0.3" [[deps.TableOperations]] deps = ["SentinelArrays", "Tables", "Test"] git-tree-sha1 = "e383c87cf2a1dc41fa30c093b2a19877c83e1bc1" uuid = "ab02a1b2-a7df-11e8-156e-fb1833f50b87" version = "1.2.0" [[deps.TableTraits]] deps = ["IteratorInterfaceExtensions"] git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" version = "1.0.1" [[deps.Tables]] deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] git-tree-sha1 = "1544b926975372da01227b382066ab70e574a3ec" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" version = "1.10.1" [[deps.Tar]] deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" version = "1.10.0" [[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" version = "0.1.1" [[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [[deps.TranscodingStreams]] deps = ["Random", "Test"] git-tree-sha1 = "9a6ae7ed916312b41236fcef7e0af564ef934769" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.9.13" [[deps.Tricks]] git-tree-sha1 = "aadb748be58b492045b4f56166b5188aa63ce549" uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" version = "0.1.7" [[deps.URIs]] git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" version = "1.4.2" [[deps.UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" [[deps.UnicodeFun]] deps = ["REPL"] git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" version = "0.4.1" [[deps.Unzip]] git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670" uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" version = "0.1.2" [[deps.Wayland_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] git-tree-sha1 = "ed8d92d9774b077c53e1da50fd81a36af3744c1c" uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" version = "1.21.0+0" [[deps.Wayland_protocols_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" version = "1.25.0+0" [[deps.Widgets]] deps = ["Colors", "Dates", "Observables", "OrderedCollections"] git-tree-sha1 = "fcdae142c1cfc7d89de2d11e08721d0f2f86c98a" uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62" version = "0.6.6" [[deps.WoodburyMatrices]] deps = ["LinearAlgebra", "SparseArrays"] git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3" uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" version = "0.5.5" [[deps.XML2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] git-tree-sha1 = "93c41695bc1c08c46c5899f4fe06d6ead504bb73" uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" version = "2.10.3+0" [[deps.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" [[deps.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" [[deps.Xorg_libXau_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" version = "1.0.9+4" [[deps.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" [[deps.Xorg_libXdmcp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" version = "1.1.3+4" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.Xorg_libpthread_stubs_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" version = "0.1.0+3" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.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" [[deps.Xorg_xtrans_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" version = "1.4.0+3" [[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" version = "1.2.13+0" [[deps.Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "49ce682769cd5de6c72dcf1b94ed7790cd08974c" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" version = "1.5.5+0" [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" version = "3.4.0+0" [[deps.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" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" version = "5.8.0+0" [[deps.libfdk_aac_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" version = "2.0.2+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" version = "1.6.38+0" [[deps.libvorbis_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" version = "1.3.7+1" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" version = "1.48.0+0" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" version = "17.4.0+0" [[deps.x264_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" version = "2021.5.5+0" [[deps.x265_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" version = "3.5.0+0" [[deps.xkbcommon_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] git-tree-sha1 = "9ebfc140cc56e8c2156a15ceac2f0302e327ac0a" uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" version = "1.4.1+0" """ # ╔═╡ Cell order: # ╟─bbe20904-d70a-438d-b46a-889ddfb8bab3 # ╟─e08d7569-68d5-4da6-b8fa-085ed6a312f6 # ╟─63ae9b00-344d-4726-8d21-a0bdc75ee8be # ╟─f7cdde7d-884d-4116-9d40-0b2f68e71e6a # ╟─8cd04c88-4ea4-4594-b0ab-a145096b3122 # ╟─3a57871a-8ccf-11ec-3c6c-d525f4e8b5c2 # ╟─513cf0e8-b7db-447c-b04a-a2e2fa17fb32 # ╟─97fba57b-8d2a-49c9-a18a-58eb2fe651eb # ╟─78784cae-f749-4a0f-89cc-46dfa4994d3a # ╟─f2f61669-6cbd-460d-9a48-454634f86579 # ╟─cf014e6b-9e74-4abf-9532-540f4bb6f43f # ╟─287bac5f-8932-4d8f-a114-39f4e071ba26 # ╟─e1b0bacc-a173-4084-bb5f-3fbd63527c23 # ╟─1ae5bc6d-16c4-40cb-846e-3b0e177fd0cf # ╟─b3634cc1-fb5f-4b7b-bfa3-08d1fb787c5f # ╟─73ed5f0e-4298-4308-bcb8-7c1245ebf0f5 # ╟─cc938f64-41f9-478b-a136-ae0cc55b5f48 # ╟─aec0ff6e-ac6a-4104-83c1-f70e254602b9 # ╟─dbffcc35-ba67-4468-b1b5-1c38a0fd971e # ╟─d969e49e-0a0c-4bdf-aba2-835586c87e7f # ╟─c0615490-3d43-4c42-9ac6-c4fdd59aae7f # ╟─ae8a3f9b-12cf-4802-8ae5-31546d82516d # ╟─7960408a-d922-43e2-9a61-4aaf0c9e6a39 # ╟─b56c3502-4dd9-4446-acd9-dcb0c667803f # ╟─76279a22-3afe-46e1-829f-88f5dddfd55c # ╟─cde13c7c-fbc2-4a8d-9b82-7607d71bb4b1 # ╟─a8843a99-cd5d-47fa-810b-68b56e405af9 # ╟─c3f3a0c3-8523-43aa-8a8a-589f567399c9 # ╟─f60fbae0-a6bd-4791-b38b-9e29ae801a07 # ╟─b95121b9-4b58-4086-bbd8-ecd2893060dd # ╟─3ff18976-beb4-45ad-aa29-d511e5d3ad0a # ╟─c563818e-d117-47ce-abeb-5b048edad64e # ╟─650ab9f4-581b-4190-8dd0-91c6d4c86b6b # ╟─1b88eacd-754b-4b6b-a8e0-dd35ae37f248 # ╟─acbab47e-2ab5-443a-8d78-f597a4ca08ed # ╟─230c1126-6717-4a93-9013-5f0c15616904 # ╟─5974ceb3-1e82-4183-9dca-35ccd6b9a9ba # ╟─fac7b990-552e-4353-8264-ba0840a95383 # ╟─4bcfb185-4499-422d-9439-6ca4e30c4846 # ╟─174dbb25-12ba-460d-a905-8223f8241964 # ╟─27a1f0cc-a6bc-417e-9c58-6b63172f753f # ╟─c9e530b7-f5f6-4905-8c6c-69ea2440f57d # ╟─67a5b4cc-00dd-4f8f-a408-27f1d8c60e7c # ╟─489676a6-b6cb-46dc-9898-feedcc2b61dd # ╟─8655b8fd-ef08-441f-9186-e2febce6e8f1 # ╟─e16bb608-d97b-40eb-bf6b-4199ee4d1926 # ╟─475aecd7-123f-4e4a-b004-90c2a8a951d8 # ╟─59be55be-5847-4fa1-a4f6-ef8e0658da13 # ╟─2e002135-2a74-47bb-92a6-520d84e85bf3 # ╟─764c0716-5dd2-4d3c-9489-1dd92d29d7c7 # ╟─274dd1f3-2a8c-4d4f-b8e2-a61e2f7bdef4 # ╟─e7ac36db-6496-4f0b-b961-1f180ca3622d # ╟─d97fd9ab-1422-4c39-85e6-d5306c690310 # ╟─6ce5a769-a05b-4a72-b2a6-46f61c530c3a # ╟─1a31ebb3-b512-45b9-9f55-2a7b173ff2c7 # ╟─05a64770-4015-438e-83ee-2d84d2277055 # ╟─5a7ec049-1092-4096-b5d9-4d2f84c6be41 # ╟─492cba29-1b5f-4f31-80e6-32dcab025f2f # ╟─830a7a78-0cb1-4ed1-906e-dd89bad6150f # ╟─fb735670-d29b-43bd-a88b-ff79d489e0b0 # ╟─05ee0bd3-320d-4d8c-993e-f2e587d78dd8 # ╟─c89378e2-424e-4a46-8c95-7fe97faafddd # ╟─7cdf9477-d2a6-4846-9f4d-7f1df14f3c58 # ╟─49747114-1019-4478-984a-759887bd9b72 # ╟─9607de34-a8a6-4be3-b603-bf2a20e73fde # ╟─ca1d1182-f77b-4510-89be-e286818c41f3 # ╟─dc971adc-b6bc-4853-afde-a163e28ebbd3 # ╟─9faecaf8-9a6a-41b4-a7e0-a9a65f039825 # ╟─1a381029-c50a-4631-8982-e9d90543ad44 # ╟─57f39905-d77f-43f9-ab8a-c8941393498a # ╟─45b844b0-0b5e-433f-9590-70b001dceff2 # ╟─e328d40b-3ba4-4fc7-b52d-aafd62f589f2 # ╟─709a5e59-545d-4b39-8b82-0c9fd2232d3b # ╟─eaedfd74-c98f-4f8f-b311-09b49839f16a # ╟─8d896695-50eb-4b66-a60c-10ea12cf2417 # ╟─da89e6ff-5d19-48df-9106-140619914220 # ╟─b133aaf9-9943-4ef7-a7ce-11daea4a3692 # ╟─797f62e6-c573-4edc-90eb-c258592e299a # ╟─c037620f-6644-40da-a045-2a68ae2464a0 # ╟─ee234a83-5f87-42c5-85d2-9a8a609a132c # ╟─e90f4ee5-d0dc-4a43-a6ae-471c65f880fe # ╟─3a5533f2-881a-4b99-96e4-4ce4bd640aec # ╟─fdfb04a5-3bf1-4a71-8433-1221e8fbcce4 # ╟─a4826006-73e0-4b15-9813-0ab5cabf25ff # ╟─2e2847a7-d102-46dc-b6cf-3767354ec003 # ╟─ecdf5365-32b2-470e-bfa4-4ade78683841 # ╟─1daa22b9-335f-436d-bf4d-053637374978 # ╟─28a84673-b849-4ccb-a488-9db4fe1818f6 # ╟─3a7e6fd6-9e54-41a0-90e3-a5d047e7e3de # ╟─4a66976a-9f51-4bfa-971b-2d922134f196 # ╟─32d4e51b-8599-4d93-905a-cb4a719710d3 # ╟─7db8d120-6c7e-4394-9336-9f66de7039be # ╟─6c2d038e-b1cf-49d1-8e7e-da9d883b8c35 # ╟─2f7ad872-4215-4d84-a30d-d3486979dd32 # ╟─f77b33d9-57a1-4659-9a68-b89184838653 # ╟─aab70bb0-5328-4044-a16a-4291c1583c9b # ╟─c00837b6-cd15-479e-96cb-065aa4411283 # ╟─5029374a-16c2-47aa-a057-84fcfc0e6c64 # ╟─646d190f-b362-42a1-85ca-d7ba7c1c63ef # ╟─893b847a-b149-4059-ab12-2536bc86c1b6 # ╟─d6987fe4-d170-4be0-9f71-8956a6eddcea # ╟─a6157e42-aa4b-4293-acf2-83dba61bd87a # ╟─f0c2aaa2-dc18-42a1-be07-5fac922e82d9 # ╟─1ecdda8a-d979-47b1-8e31-1511bd711302 # ╟─ae597ea1-5e3c-45c2-8a5a-808abf4b8a69 # ╟─9da8dadd-e786-4376-9d99-8b98ab44c24c # ╟─c475163f-fc56-424f-aa63-4cce2b7b1a91 # ╟─6c6ff49d-569e-4998-add9-c23051713318 # ╟─299b92f6-8f13-4a51-b831-22f05bcc312d # ╟─1eefc8b3-d3f4-4e6f-a93d-5f4ab6bab40c # ╟─39cea09d-5088-475b-bd09-19e6671752c8 # ╟─95a9918a-7223-4f69-98f0-c70425db2355 # ╟─e82a9905-eb01-43b6-bf2d-050548f33df9 # ╟─c8448dfc-1b07-43f0-9728-252a90bbba51 # ╟─c7f093d9-5a8a-4c18-ac65-f1b03673a14d # ╟─300fdf66-84d8-4ca0-b84e-af1deb3945ac # ╟─e0f2cb2c-4b7b-4a24-b0a0-50db401d963e # ╟─f1dc867a-5683-4218-9723-25fb98d92875 # ╟─9797d171-bc06-4697-9ead-4a18b4327f49 # ╟─f037c06f-db56-4c46-9fa1-88c52e6943b9 # ╟─e7c84285-20ef-44b6-82af-52ccc6e98163 # ╟─dca00dac-cccd-448a-a4a2-2a38b981d2e7 # ╟─7439ea28-5e00-4a5a-ad0c-6b23771df9ea # ╟─ae215d41-addb-4694-867c-4720cd6835a1 # ╟─494bedcf-1e3a-44d6-a51f-8c29cfb50830 # ╟─d12f3d01-ed74-4204-82e6-19f43e559699 # ╟─f769a263-d8df-4b40-9de7-3d6517095557 # ╟─247bf9c5-4f0a-4ed2-a604-1e9ef8b64b01 # ╟─9c95a7a3-bd09-4a69-a5b2-ec39f4e3d868 # ╟─d33bd7b5-904b-4fbf-964e-5f32a34d26a6 # ╟─109586dd-7ff7-4d09-981c-173775a0debb # ╟─2afd14dd-78e5-4205-93df-c5020ab3253f # ╟─13f60f6b-3bac-4ba7-9ae6-233fac4bbfdd # ╟─bd53b23f-9aaf-4fce-af04-0b8592d646be # ╟─f6625979-61d8-4e17-b4fa-0c673c53edea # ╟─b7254213-a06b-45c7-a1cb-e799a0cc4844 # ╟─4b54f396-a3a6-4fde-bf1c-11b8c4579c21 # ╟─2ae06afc-1cb2-485a-8b05-e9c76b7aa4e4 # ╟─f4f00c5d-7bad-4261-a683-ef374ccde1d8 # ╟─5399561a-f4d1-465f-88da-9452746625b8 # ╟─6256ef07-6188-41fe-bddc-c006cba557bd # ╟─14f43c7e-fdb1-4bc5-8820-dcc90ebff3b7 # ╟─49c73149-e31a-41f0-8857-7d4a035e098f # ╟─9b4befdd-8ed9-4269-9a7e-0e8afc10eaa9 # ╟─abf219da-d9bf-410f-9c3f-14ddbd5fbb34 # ╟─8cebf3fb-1db5-42b7-9214-b53e8607bff2 # ╟─435410b9-d7c5-4aba-989c-58ffbbd93c6e # ╟─54bd596e-4d22-4894-b2e0-63f424f3a540 # ╟─232c1de0-5ec4-4c64-904c-4bc9acd098df # ╟─2d5c6ac0-4eed-4f2e-8600-42e605a47f22 # ╟─ca95bbed-d34a-4d15-980a-d3aeaf2bbada # ╟─0a850a9e-6c57-4d8f-9d60-07113b004967 # ╟─a5e5700a-0c01-47b5-ae00-0bdc86cacc4e # ╟─7a39222f-6155-41c6-a1fe-66ecc42203b8 # ╟─740501ba-2e31-4ff4-968e-1dfb33cbbe78 # ╟─2a93b54d-4d97-4850-83df-47f0902fc72f # ╟─57c14c36-e5c6-4049-ba2d-79e5825533b1 # ╟─635832fe-1b8c-40c0-9b94-968f449c89e6 # ╟─7bb25bbc-f4b4-41d6-bd4b-17df602d0fd5 # ╟─e6038ed1-95d1-4241-99d4-5789b0715981 # ╟─dd6e50f2-d3d9-4810-a064-8404f9189f7a # ╟─d92d7f39-7e4b-40b8-93a3-118c2ea03db5 # ╟─be37333b-4350-4405-9f2f-80b3a5f566a7 # ╟─1c38a45b-d50f-48f6-831e-d3b4b2fe9641 # ╟─0909842d-2a28-4c11-92dd-e95acd070c41 # ╟─602994bf-c91d-4f39-8286-405d4bcede38 # ╟─80b2e36a-5464-454a-a5cd-6980e89aa5b7 # ╟─af94b4a6-94bc-4a8e-956a-488c050a7b20 # ╟─7f3da391-00db-4d83-a617-044503b92acf # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002