From d142f2bfdc7b5ff0107ad56bf3db0a8613275e65 Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Fri, 17 Nov 2023 00:19:58 -0300 Subject: [PATCH 01/13] Update paper.md --- joss/paper.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/joss/paper.md b/joss/paper.md index 4a9ad531..a12fd547 100644 --- a/joss/paper.md +++ b/joss/paper.md @@ -8,16 +8,14 @@ authors: orcid: 0000-0002-7508-999X corresponding: true affiliation: 1 - - name: YOUR NAME - orcid: 0000-0000-0000-0000 - affiliation: "2, 3" # must use "" if you have more than one. + - name: Santiago Jimenez + orcid: 0000-0002-8198-3656 + affiliation: 2 # must use "" if you have more than one. affiliations: - name: SESSTIM, Aix Marseille University, Marseille, France index: 1 - - name: YOUR FIRST AFFILIATION + - name: Federal University of Pernambuco index: 2 - - name: YOUR SECOND AFFILIATION - index: 3 date: 16 November 2023 bibliography: paper.bib @@ -155,4 +153,4 @@ The package is starting to get used in several other places of the ecosystem. Am -# References \ No newline at end of file +# References From 49bcc950b911965e46216ea024070ecb3b76d110 Mon Sep 17 00:00:00 2001 From: Santymax98 Date: Mon, 20 Nov 2023 15:20:39 -0300 Subject: [PATCH 02/13] new file: src/Plotly_functions.jl new file: test/test_plotly.jl --- src/Plotly_functions.jl | 227 ++++++++++++++++++++++++++++++++++++++++ test/test_plotly.jl | 74 +++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 src/Plotly_functions.jl create mode 100644 test/test_plotly.jl diff --git a/src/Plotly_functions.jl b/src/Plotly_functions.jl new file mode 100644 index 00000000..54a8b2bd --- /dev/null +++ b/src/Plotly_functions.jl @@ -0,0 +1,227 @@ +using Plotly, Distributions, Copulas + +function plotly_copula(copula, data::AbstractMatrix, function_type::AbstractString; col = "Viridis", title="", xlabel="u", ylabel="v", show_contours = true, scale = true) + #Validate the type of function entered + validate_function_type(function_type) + + colors_3D = ["Blackbody", "Bluered", "Blues", "Cividis", "Earth", "Electric", "Greens", "Greys", "Hot", + "Jet" , "Picnic", "Portland", "Rainbow", "RdBu", "Reds", "Viridis", "YlGnBu", "YlOrRd"] + #Check copula length + if length(copula) == 2 + if function_type == "scatter3d" + error("Cannot use 'scatter3d' when copula length is 2.") + end + elseif length(copula) == 3 + if function_type != "scatter3d" + error("You can only use 'scatter3d' when the copula length is 3.") + end + else + error("The copula length must be 2 or 3.") + end + + if function_type == "scatter" + if col in colors_3D + col = "lightblue" + end + return plotly_scatter(data, col, title, xlabel, ylabel) + elseif function_type == "scatter+hist" + if col in colors_3D + col = "lightblue" + end + return plotly_scatter_hist(data, col) + elseif function_type == "hist2D" + if !(col in colors_3D) + @warn("The color '$col' is not in Plotly's predefined list. 'YlGnBu' will be used as the default color.") + println("Possible predefined colors in Plotly:") + println(colors_3D) + col = "YlGnBu" + end + return plot_histogram_2D(data, col, title, xlabel, ylabel) + elseif (function_type == "pdf_contours" || function_type == "cdf_contours") + if !(col in colors_3D) + @warn("The color '$col' is not in Plotly's predefined list. 'Viridis' will be used as the default color.") + println("Possible predefined colors in Plotly:") + println(colors_3D) + col = "Viridis" + end + return plotly_contours(copula, function_type, col, title, xlabel, ylabel, scale) + elseif function_type == "scatter3d" + return plotly_scatter3D(copula, data, col) + else + #Check if the color is in the predefined list + if !(col in colors_3D) + @warn("The color '$col' is not in Plotly's predefined list. 'Viridis' will be used as the default color.") + println("Possible predefined colors in Plotly:") + println(colors_3D) + col = "Viridis" + end + return plotly_surface(copula, function_type, col, title, xlabel, ylabel, show_contours, scale) + end +end + +function validate_function_type(function_type) + if !(function_type in ["pdf", "cdf", "scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "scatter3d"]) + error("The function must be 'pdf', 'cdf', 'scatter', 'scatter+hist', 'hist2D', 'pdf_contours', 'cdf_contours', 'scatter3d'") + end +end + +function plotly_scatter(data, col, title, xlabel, ylabel) + scatter_plotly = Plotly.scatter( + x=data[1, :], + y=data[2, :], + mode="markers", + marker=attr(color=col, size=3) + ) + + layout = create_layout(title, xlabel, ylabel) + + return Plotly.plot(scatter_plotly, layout) +end + +function plotly_scatter_hist(data, col) + trace1 = Plotly.scatter(x=data[1, :], y=data[2, :], mode="markers", marker=attr(color=col, size=3)) + trace2 = Plotly.histogram(x=data[1, :], xaxis="x", yaxis="y2", marker=attr(color="#c7f6d4")) + trace3 = Plotly.histogram(y=data[2, :], xaxis="x2", yaxis="y", marker=attr(color="#caacf9")) + + layout = create_scatter_hist_layout() + + return Plotly.plot([trace1, trace2, trace3], layout) +end + +function plotly_histogram_2D(data, col, title, xlabel, ylabel) + layout = create_hist_2D_layout(title, xlabel, ylabel) + return Plotly.plot(histogram2d(x=data[1, :], y=data[2, :], colorscale=col),layout) +end + +function plotly_contours(copula, function_type, col, title, xlabel, ylabel, scale) + u = range(0, stop=1, length=100) + v = range(0, stop=1, length=100) + grid = Iterators.product(u, v) + + z_data = [calculate_value(copula, ui, vi, function_type) for (ui, vi) in grid] + z_data = reshape(z_data, 100, 100) + layout = create_countors_layout(title, xlabel, ylabel) + return Plotly.plot(contour(x=u,y=v, z=z_data, colorscale=col, showscale=scale),layout) +end + +function plotly_surface(copula, function_type, col, title, xlabel, ylabel, show_contours, scale) + u = range(0, stop=1, length=100) + v = range(0, stop=1, length=100) + grid = Iterators.product(u, v) + + z_data = [calculate_value(copula, ui, vi, function_type) for (ui, vi) in grid] + z_data = reshape(z_data, 100, 100) + + layout = create_surface_layout(title, xlabel, ylabel, show_contours, scale, col, function_type) + + return Plotly.plot(surface(x=u, y=v, z=z_data, contours_z=show_contours, colorscale=col, showscale=scale), layout) +end + +function calculate_value(copula, ui, vi, function_type) + if (function_type == "pdf" || function_type == "pdf_contours") + return pdf(copula, [ui, vi]) + elseif (function_type == "cdf" || function_type == "cdf_contours") + return cdf(copula, [ui, vi]) + end +end + +function plotly_scatter3D(copula, data, col) + layout = Layout( + scene = attr( + xaxis_title = "u", + yaxis_title = "v", + zaxis_title = "w" + )) + return Plotly.plot(scatter3d(x = data[1, :], y = data[2, :], z = data[3, :], + mode = "markers", + marker = attr(size = 3, color = data[3, :], colorscale=col + )),layout) +end + +function create_layout(title, xlabel, ylabel) + return Plotly.Layout( + title=title, + xaxis_title=xlabel, + yaxis_title=ylabel, + plot_bgcolor="white", + paper_bgcolor="white", + xaxis=create_axis_properties(), + yaxis=create_axis_properties() + ) +end + +function create_scatter_hist_layout() + return Plotly.Layout( + autosize=false, + plot_bgcolor="white", + paper_bgcolor="white", + xaxis=create_axis_properties(zeroline=false, domain=[0, 0.81]), + yaxis=create_axis_properties(zeroline=false, domain=[0, 0.81]), + xaxis2=create_axis_properties(zeroline=false, domain=[0.85, 1]), + yaxis2=create_axis_properties(zeroline=true, domain=[0.85, 1]), + height=600, + width=600, + bargap=0, + showlegend=false + ) +end + +function create_hist_2D_layout(title, xlabel, ylabel) + return Plotly.Layout( + title = title, + xaxis=attr(title=xlabel, showgrid=false, zeroline=false), + yaxis=attr(title=ylabel, showgrid=false, zeroline=false), + autosize=false, + height=500, + width=500, + hovermode="closest", + showlegend=false + ) +end + +function create_surface_layout(title, xlabel, ylabel, show_contours, scale, col, function_type) + contours_settings = show_contours ? attr(show=true, usecolormap=true, project_z=true, showlines=true) : false + + zaxis_title = function_type == "pdf" ? "PDF" : (function_type == "cdf" ? "CDF" : "function_type") + + return Plotly.Layout( + title=title, + autosize=false, + scene_camera_eye=attr(x=1.87, y=0.88, z=-0.64), + width=500, + height=500, + margin=attr(l=65, r=50, b=65, t=90), + scene=attr(xaxis_title=xlabel, yaxis_title=ylabel, zaxis_title=zaxis_title), + xaxis=create_axis_properties(), + yaxis=create_axis_properties(), + showlegend=false + ) +end + +function create_axis_properties(; zeroline=true, domain=[0, 1], showgrid=true, gridcolor="#FAFAFA", gridwidth=0.5, griddash="solid", showline=true, linecolor="black") + return attr( + zeroline=zeroline, + domain=domain, + showgrid=showgrid, + gridcolor=gridcolor, + gridwidth=gridwidth, + griddash=griddash, + showline=showline, + linecolor=linecolor + ) +end + +function create_countors_layout(title, xlabel, ylabel) + return Plotly.Layout( + title = title, + xaxis = attr(title = xlabel, showgrid = false, zeroline = false), + yaxis = attr(title = ylabel, showgrid = false, zeroline = false), + autosize = false, + height = 500, + width = 500, + hovermode = "closest", + showlegend = false + ) +end + + diff --git a/test/test_plotly.jl b/test/test_plotly.jl new file mode 100644 index 00000000..4047f705 --- /dev/null +++ b/test/test_plotly.jl @@ -0,0 +1,74 @@ +using Test +# Test function for plotly_copula +function test_plotly_copula_methods() + # Create data and copula for testing + X1 = Gamma(2, 3) + X2 = Pareto() + C = ClaytonCopula(2, 3.5) + D = SklarDist(C, (X1, X2)) + samples = rand(D, 1000) + + # Methods to try + methods = ["pdf", "cdf", "scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "scatter3d"] + + for method in methods + println("Testing method: $method") + + if method == "scatter3d" && length(D) == 2 + # Test 1: Verify that plotly_copula generates an error for scatter3d with bivariate copula + @test_throws ErrorException plotly_copula(D, samples, method) + else + # Test 1: Verify that plotly_copula does not throw errors + result = plotly_copula(D, samples, method) + + # Test 2: Verify that plotly_copula generates a plot + @test isa(result, PlotlyJS.SyncPlot) + end + end +end + + +@testset "Graphics Function Tests" begin + test_plotly_copula_methods() +end + +# Función de prueba para plotly_copula +function test_multivariate_copula_methods() + # Methods to prove + Methods = ["scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "pdf", "cdf"] + + for method in Methods + for i in [4, 5,6] + D_mult = InvGaussianCopula(i, 2.5) + samples_mult = rand(D_mult, 300) + println("Testing method for multivariate copula: $method") + @test_throws ErrorException plotly_copula(D_mult, samples_mult, method) + end + end + + # Trivariate prove + for method in Methods + for i in [1, 2, 3] + T = JoeCopula(3, i) + samples_tri = rand(T, 1000) + + try + if length(T) == 3 && method == "scatter3d" + result = plotly_copula(T, samples_tri, method) + @test isa(result, PlotlyJS.SyncPlot) + else + println("Testing method for trivariate copula: $method") + @test_throws ErrorException plotly_copula(T, samples_tri, method) + end + catch ex + println("Error in method $method for trivariate copula: $ex") + end + end + end +end + +# Ejecutar la prueba +@testset "Tests de funciones de gráficos para copulas multivariadas" begin + test_multivariate_copula_methods() +end + From 30fcb75bb674be6032e031bacc563870f68db0eb Mon Sep 17 00:00:00 2001 From: Santymax98 Date: Wed, 29 Nov 2023 22:53:20 -0300 Subject: [PATCH 03/13] new file: src/MiscellaneousCopulas/RafteryCopula.jl deleted: src/Plotly_functions.jl new file: test/RafteryTest.jl deleted: test/test_plotly.jl --- src/MiscellaneousCopulas/RafteryCopula.jl | 106 ++++++++++ src/Plotly_functions.jl | 227 ---------------------- test/RafteryTest.jl | 42 ++++ test/test_plotly.jl | 74 ------- 4 files changed, 148 insertions(+), 301 deletions(-) create mode 100644 src/MiscellaneousCopulas/RafteryCopula.jl delete mode 100644 src/Plotly_functions.jl create mode 100644 test/RafteryTest.jl delete mode 100644 test/test_plotly.jl diff --git a/src/MiscellaneousCopulas/RafteryCopula.jl b/src/MiscellaneousCopulas/RafteryCopula.jl new file mode 100644 index 00000000..fc1ceb6f --- /dev/null +++ b/src/MiscellaneousCopulas/RafteryCopula.jl @@ -0,0 +1,106 @@ +""" + RafteryCopula{d, P} + +Fields: + - θ::Real - parameter + +Constructor + + RafteryCopula(d, θ) + +The Multivariate Raftery Copula of dimension d is arameterized by ``\\theta \\in [0,1]`` + +```math +C_{\\theta}(\\mathbf{u}) = u_{(1)} + \\frac{(1 - \\theta)(1 - d)}{1 - \\theta - d} \\left(\\prod_{j=1}^{d} u_j\\right)^{\\frac{1}{1-\\theta}} - \\sum_{i=2}^{d} \\frac{\\theta(1-\\theta)}{(1-\\theta-i)(2-\\theta-i)} \\left(\\prod_{j=1}^{i-1}u_{(j)}\\right)^{\\frac{1}{1-\\theta}}u_{(i)}^{\\frac{2-\\theta-i}{1-\\theta}} +``` + + +where ``u_{(1)}, \\ldots , u_{(d)}`` denote the order statistics of ``u_1, \\ldots ,u_d``. + +More details about Multivariate Raftery Copula are found in : + + Saali, T., M. Mesfioui, and A. Shabri, 2023: Multivariate Extension of Raftery Copula. Mathematics, 11, 414, https://doi.org/10.3390/math11020414. + + Nelsen, Roger B. An introduction to copulas. Springer, 2006. Exercise 3.6. + +It has a few special cases: +- When θ = 0, it is the IndependentCopula. +- When θ = 1, it is the the Fréchet upper bound +""" +struct RafteryCopula{d, P} <: Copula{d} + θ::P # Copula parameter + function RafteryCopula(d,θ) + if (θ < 0) || (θ > 1) + throw(ArgumentError("Theta must be in [0,1]")) + elseif θ == 0 + return IndependentCopula(d) + elseif θ == 1 + return MCopula(d) + else + return new{d,typeof(θ)}(θ) + end + end +end +function _cdf(R::RafteryCopula, u::Vector{T}) where {T} + if length(u) != R.d + throw(ArgumentError("Dimension mismatch")) + end + + # Order the vector u + u_ordered = sort(u) + + term1 = u_ordered[1] + term2 = (1 - R.θ) * (1 - R.d) / (1 - R.θ - R.d) * prod(u).^(1/(1 - R.θ)) + + term3 = 0.0 + for i in 2:R.d + prod_prev = prod(u_ordered[1:i-1]) + term3 += R.θ * (1 - R.θ) / ((1 - R.θ - i) * (2 - R.θ - i)) * prod_prev^(1/(1 - R.θ)) * u_ordered[i]^((2 - R.θ - i) / (1 - R.θ)) + end + # Combine the terms to get the cumulative distribution function + cdf_value = term1 + term2 - term3 + + return cdf_value +end + +function Distributions._logpdf(R::RafteryCopula, u::Vector{T}) where {T} + if length(u) != R.d + throw(ArgumentError("Dimension mismatch")) + end + + # Order the vector u + u_ordered = sort(u) + + term_denominator = (1 - R.θ)^(R.d - 1) * (1 - R.θ - R.d) + term_numerator = 1 - R.d - R.θ * u_ordered[R.d]^((1 - R.θ - R.d) / (1 - R.θ)) + term_product = prod(u)^((R.θ) / (1 - R.θ)) + + logpdf_value = log(term_numerator) - log(term_denominator) + log(term_product) + + return logpdf_value +end + +function Distributions._rand!(rng::Distributions.AbstractRNG, R::RafteryCopula{d,P}, x::AbstractVector{T}) where {d,P,T <: Real} + + dim = length(x) + + # Paso 1: Generar valores independientes u, u_1, ..., u_d desde una distribución uniforme [0, 1] + u = rand(rng, dim+1) + + # Paso 2: Generar j desde una distribución de Bernoulli con parámetro θ + j = rand(Bernoulli(R.θ),1) + uj = u[1].^j + # Paso 3: Calcular v_1, ..., v_d + for i in 2:dim+1 + x[i] = u[i]^(1 - R.θ) * uj + end + + return x +end + +function ρ(R::RafteryCopula{d,R}) where {d, P} + term1 = (d+1)*(2^d-(2-R.θ)^d)-(2^d*R.θ*d) + term2 = (2-R.θ)^d*(2^d-d-1) + return term1/term2 +end + diff --git a/src/Plotly_functions.jl b/src/Plotly_functions.jl deleted file mode 100644 index 54a8b2bd..00000000 --- a/src/Plotly_functions.jl +++ /dev/null @@ -1,227 +0,0 @@ -using Plotly, Distributions, Copulas - -function plotly_copula(copula, data::AbstractMatrix, function_type::AbstractString; col = "Viridis", title="", xlabel="u", ylabel="v", show_contours = true, scale = true) - #Validate the type of function entered - validate_function_type(function_type) - - colors_3D = ["Blackbody", "Bluered", "Blues", "Cividis", "Earth", "Electric", "Greens", "Greys", "Hot", - "Jet" , "Picnic", "Portland", "Rainbow", "RdBu", "Reds", "Viridis", "YlGnBu", "YlOrRd"] - #Check copula length - if length(copula) == 2 - if function_type == "scatter3d" - error("Cannot use 'scatter3d' when copula length is 2.") - end - elseif length(copula) == 3 - if function_type != "scatter3d" - error("You can only use 'scatter3d' when the copula length is 3.") - end - else - error("The copula length must be 2 or 3.") - end - - if function_type == "scatter" - if col in colors_3D - col = "lightblue" - end - return plotly_scatter(data, col, title, xlabel, ylabel) - elseif function_type == "scatter+hist" - if col in colors_3D - col = "lightblue" - end - return plotly_scatter_hist(data, col) - elseif function_type == "hist2D" - if !(col in colors_3D) - @warn("The color '$col' is not in Plotly's predefined list. 'YlGnBu' will be used as the default color.") - println("Possible predefined colors in Plotly:") - println(colors_3D) - col = "YlGnBu" - end - return plot_histogram_2D(data, col, title, xlabel, ylabel) - elseif (function_type == "pdf_contours" || function_type == "cdf_contours") - if !(col in colors_3D) - @warn("The color '$col' is not in Plotly's predefined list. 'Viridis' will be used as the default color.") - println("Possible predefined colors in Plotly:") - println(colors_3D) - col = "Viridis" - end - return plotly_contours(copula, function_type, col, title, xlabel, ylabel, scale) - elseif function_type == "scatter3d" - return plotly_scatter3D(copula, data, col) - else - #Check if the color is in the predefined list - if !(col in colors_3D) - @warn("The color '$col' is not in Plotly's predefined list. 'Viridis' will be used as the default color.") - println("Possible predefined colors in Plotly:") - println(colors_3D) - col = "Viridis" - end - return plotly_surface(copula, function_type, col, title, xlabel, ylabel, show_contours, scale) - end -end - -function validate_function_type(function_type) - if !(function_type in ["pdf", "cdf", "scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "scatter3d"]) - error("The function must be 'pdf', 'cdf', 'scatter', 'scatter+hist', 'hist2D', 'pdf_contours', 'cdf_contours', 'scatter3d'") - end -end - -function plotly_scatter(data, col, title, xlabel, ylabel) - scatter_plotly = Plotly.scatter( - x=data[1, :], - y=data[2, :], - mode="markers", - marker=attr(color=col, size=3) - ) - - layout = create_layout(title, xlabel, ylabel) - - return Plotly.plot(scatter_plotly, layout) -end - -function plotly_scatter_hist(data, col) - trace1 = Plotly.scatter(x=data[1, :], y=data[2, :], mode="markers", marker=attr(color=col, size=3)) - trace2 = Plotly.histogram(x=data[1, :], xaxis="x", yaxis="y2", marker=attr(color="#c7f6d4")) - trace3 = Plotly.histogram(y=data[2, :], xaxis="x2", yaxis="y", marker=attr(color="#caacf9")) - - layout = create_scatter_hist_layout() - - return Plotly.plot([trace1, trace2, trace3], layout) -end - -function plotly_histogram_2D(data, col, title, xlabel, ylabel) - layout = create_hist_2D_layout(title, xlabel, ylabel) - return Plotly.plot(histogram2d(x=data[1, :], y=data[2, :], colorscale=col),layout) -end - -function plotly_contours(copula, function_type, col, title, xlabel, ylabel, scale) - u = range(0, stop=1, length=100) - v = range(0, stop=1, length=100) - grid = Iterators.product(u, v) - - z_data = [calculate_value(copula, ui, vi, function_type) for (ui, vi) in grid] - z_data = reshape(z_data, 100, 100) - layout = create_countors_layout(title, xlabel, ylabel) - return Plotly.plot(contour(x=u,y=v, z=z_data, colorscale=col, showscale=scale),layout) -end - -function plotly_surface(copula, function_type, col, title, xlabel, ylabel, show_contours, scale) - u = range(0, stop=1, length=100) - v = range(0, stop=1, length=100) - grid = Iterators.product(u, v) - - z_data = [calculate_value(copula, ui, vi, function_type) for (ui, vi) in grid] - z_data = reshape(z_data, 100, 100) - - layout = create_surface_layout(title, xlabel, ylabel, show_contours, scale, col, function_type) - - return Plotly.plot(surface(x=u, y=v, z=z_data, contours_z=show_contours, colorscale=col, showscale=scale), layout) -end - -function calculate_value(copula, ui, vi, function_type) - if (function_type == "pdf" || function_type == "pdf_contours") - return pdf(copula, [ui, vi]) - elseif (function_type == "cdf" || function_type == "cdf_contours") - return cdf(copula, [ui, vi]) - end -end - -function plotly_scatter3D(copula, data, col) - layout = Layout( - scene = attr( - xaxis_title = "u", - yaxis_title = "v", - zaxis_title = "w" - )) - return Plotly.plot(scatter3d(x = data[1, :], y = data[2, :], z = data[3, :], - mode = "markers", - marker = attr(size = 3, color = data[3, :], colorscale=col - )),layout) -end - -function create_layout(title, xlabel, ylabel) - return Plotly.Layout( - title=title, - xaxis_title=xlabel, - yaxis_title=ylabel, - plot_bgcolor="white", - paper_bgcolor="white", - xaxis=create_axis_properties(), - yaxis=create_axis_properties() - ) -end - -function create_scatter_hist_layout() - return Plotly.Layout( - autosize=false, - plot_bgcolor="white", - paper_bgcolor="white", - xaxis=create_axis_properties(zeroline=false, domain=[0, 0.81]), - yaxis=create_axis_properties(zeroline=false, domain=[0, 0.81]), - xaxis2=create_axis_properties(zeroline=false, domain=[0.85, 1]), - yaxis2=create_axis_properties(zeroline=true, domain=[0.85, 1]), - height=600, - width=600, - bargap=0, - showlegend=false - ) -end - -function create_hist_2D_layout(title, xlabel, ylabel) - return Plotly.Layout( - title = title, - xaxis=attr(title=xlabel, showgrid=false, zeroline=false), - yaxis=attr(title=ylabel, showgrid=false, zeroline=false), - autosize=false, - height=500, - width=500, - hovermode="closest", - showlegend=false - ) -end - -function create_surface_layout(title, xlabel, ylabel, show_contours, scale, col, function_type) - contours_settings = show_contours ? attr(show=true, usecolormap=true, project_z=true, showlines=true) : false - - zaxis_title = function_type == "pdf" ? "PDF" : (function_type == "cdf" ? "CDF" : "function_type") - - return Plotly.Layout( - title=title, - autosize=false, - scene_camera_eye=attr(x=1.87, y=0.88, z=-0.64), - width=500, - height=500, - margin=attr(l=65, r=50, b=65, t=90), - scene=attr(xaxis_title=xlabel, yaxis_title=ylabel, zaxis_title=zaxis_title), - xaxis=create_axis_properties(), - yaxis=create_axis_properties(), - showlegend=false - ) -end - -function create_axis_properties(; zeroline=true, domain=[0, 1], showgrid=true, gridcolor="#FAFAFA", gridwidth=0.5, griddash="solid", showline=true, linecolor="black") - return attr( - zeroline=zeroline, - domain=domain, - showgrid=showgrid, - gridcolor=gridcolor, - gridwidth=gridwidth, - griddash=griddash, - showline=showline, - linecolor=linecolor - ) -end - -function create_countors_layout(title, xlabel, ylabel) - return Plotly.Layout( - title = title, - xaxis = attr(title = xlabel, showgrid = false, zeroline = false), - yaxis = attr(title = ylabel, showgrid = false, zeroline = false), - autosize = false, - height = 500, - width = 500, - hovermode = "closest", - showlegend = false - ) -end - - diff --git a/test/RafteryTest.jl b/test/RafteryTest.jl new file mode 100644 index 00000000..63a567f7 --- /dev/null +++ b/test/RafteryTest.jl @@ -0,0 +1,42 @@ +@testitem "RafteryCopula Constructor" begin + for d in [2,3,4] + @test isa(RarfteryCopula(d,0.0), IndependentCopula) + @test isa(RarfteryCopula(d,1.0), MCopula) + end + @test_throws ArgumentError RafteryCopula(1,0.5) + @test_throws ArgumentError RafteryCopula(3,-1.5) + @test_throws ArgumentError RafteryCopula(2, 2.6) +end + +@testset "RafteryCopula CDF" begin + + for d in [2, 3, 4] + F = RafteryCopula(d, 0.5) + + # Test CDF with some random values + u = rand(d) + cdf_value = cdf(F, u) + @test cdf_value >= 0 && cdf_value <= 1 + end +end + +@testset "RafteryCopula PDF" begin + + for d in [2, 3, 4] + F = RafteryCopula(d, 0.5) + + # Test PDF with some random values + u = rand(d) + pdf_value = pdf(F, u) + @test pdf_value >= 0 + end +end + +@testitem "RafteryCopula Sampling" begin + using StableRNGs + rng = StableRNG(123) + n_samples = 100 + F = RafteryCopula(3,0.5) + samples = rand(rng,F, n_samples) + @test size(samples) == (3, n_samples) +end \ No newline at end of file diff --git a/test/test_plotly.jl b/test/test_plotly.jl deleted file mode 100644 index 4047f705..00000000 --- a/test/test_plotly.jl +++ /dev/null @@ -1,74 +0,0 @@ -using Test -# Test function for plotly_copula -function test_plotly_copula_methods() - # Create data and copula for testing - X1 = Gamma(2, 3) - X2 = Pareto() - C = ClaytonCopula(2, 3.5) - D = SklarDist(C, (X1, X2)) - samples = rand(D, 1000) - - # Methods to try - methods = ["pdf", "cdf", "scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "scatter3d"] - - for method in methods - println("Testing method: $method") - - if method == "scatter3d" && length(D) == 2 - # Test 1: Verify that plotly_copula generates an error for scatter3d with bivariate copula - @test_throws ErrorException plotly_copula(D, samples, method) - else - # Test 1: Verify that plotly_copula does not throw errors - result = plotly_copula(D, samples, method) - - # Test 2: Verify that plotly_copula generates a plot - @test isa(result, PlotlyJS.SyncPlot) - end - end -end - - -@testset "Graphics Function Tests" begin - test_plotly_copula_methods() -end - -# Función de prueba para plotly_copula -function test_multivariate_copula_methods() - # Methods to prove - Methods = ["scatter", "scatter+hist", "hist2D", "pdf_contours", "cdf_contours", "pdf", "cdf"] - - for method in Methods - for i in [4, 5,6] - D_mult = InvGaussianCopula(i, 2.5) - samples_mult = rand(D_mult, 300) - println("Testing method for multivariate copula: $method") - @test_throws ErrorException plotly_copula(D_mult, samples_mult, method) - end - end - - # Trivariate prove - for method in Methods - for i in [1, 2, 3] - T = JoeCopula(3, i) - samples_tri = rand(T, 1000) - - try - if length(T) == 3 && method == "scatter3d" - result = plotly_copula(T, samples_tri, method) - @test isa(result, PlotlyJS.SyncPlot) - else - println("Testing method for trivariate copula: $method") - @test_throws ErrorException plotly_copula(T, samples_tri, method) - end - catch ex - println("Error in method $method for trivariate copula: $ex") - end - end - end -end - -# Ejecutar la prueba -@testset "Tests de funciones de gráficos para copulas multivariadas" begin - test_multivariate_copula_methods() -end - From 8e1aa29c25197bfa7c7a831955f1470cc5dd5fe3 Mon Sep 17 00:00:00 2001 From: Santymax98 Date: Wed, 29 Nov 2023 23:03:53 -0300 Subject: [PATCH 04/13] modified: docs/src/miscellaneous.md modified: src/Copulas.jl modified: src/MiscellaneousCopulas/RafteryCopula.jl --- docs/src/miscellaneous.md | 6 ++++++ src/Copulas.jl | 4 +++- src/MiscellaneousCopulas/RafteryCopula.jl | 9 ++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/src/miscellaneous.md b/docs/src/miscellaneous.md index 2951a9b0..6198903a 100644 --- a/docs/src/miscellaneous.md +++ b/docs/src/miscellaneous.md @@ -29,6 +29,12 @@ PlackettCopula FGMCopula ``` +# Raftery copula + +```@docs +RafteryCopula +``` + ## Survival Copula ```@docs diff --git a/src/Copulas.jl b/src/Copulas.jl index d18418ad..140c31a8 100644 --- a/src/Copulas.jl +++ b/src/Copulas.jl @@ -30,12 +30,14 @@ module Copulas include("MiscellaneousCopulas/PlackettCopula.jl") include("MiscellaneousCopulas/EmpiricalCopula.jl") include("MiscellaneousCopulas/FGMCopula.jl") + include("MiscellaneousCopulas/RafteryCopula.jl") export MCopula, WCopula, SurvivalCopula, PlackettCopula, EmpiricalCopula, - FGMCopula + FGMCopula, + RafteryCopula # Elliptical copulas include("EllipticalCopula.jl") diff --git a/src/MiscellaneousCopulas/RafteryCopula.jl b/src/MiscellaneousCopulas/RafteryCopula.jl index fc1ceb6f..df19447a 100644 --- a/src/MiscellaneousCopulas/RafteryCopula.jl +++ b/src/MiscellaneousCopulas/RafteryCopula.jl @@ -84,13 +84,13 @@ function Distributions._rand!(rng::Distributions.AbstractRNG, R::RafteryCopula{d dim = length(x) - # Paso 1: Generar valores independientes u, u_1, ..., u_d desde una distribución uniforme [0, 1] + # Step 1: Generate independent values u, u_1, ..., u_d from a uniform distribution [0, 1] u = rand(rng, dim+1) - # Paso 2: Generar j desde una distribución de Bernoulli con parámetro θ + # Step 2: Generate j from a Bernoulli distribution with parameter θ j = rand(Bernoulli(R.θ),1) uj = u[1].^j - # Paso 3: Calcular v_1, ..., v_d + # Step 3: Calculate v_1, ..., v_d for i in 2:dim+1 x[i] = u[i]^(1 - R.θ) * uj end @@ -102,5 +102,4 @@ function ρ(R::RafteryCopula{d,R}) where {d, P} term1 = (d+1)*(2^d-(2-R.θ)^d)-(2^d*R.θ*d) term2 = (2-R.θ)^d*(2^d-d-1) return term1/term2 -end - +end \ No newline at end of file From db385c2b658d486fdd138ce49562cde4516c1951 Mon Sep 17 00:00:00 2001 From: Santymax98 Date: Thu, 30 Nov 2023 10:27:07 -0300 Subject: [PATCH 05/13] modified: src/MiscellaneousCopulas/RafteryCopula.jl --- src/MiscellaneousCopulas/RafteryCopula.jl | 52 +++++++++++++---------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/MiscellaneousCopulas/RafteryCopula.jl b/src/MiscellaneousCopulas/RafteryCopula.jl index df19447a..398a1867 100644 --- a/src/MiscellaneousCopulas/RafteryCopula.jl +++ b/src/MiscellaneousCopulas/RafteryCopula.jl @@ -19,9 +19,9 @@ where ``u_{(1)}, \\ldots , u_{(d)}`` denote the order statistics of ``u_1, \\ldo More details about Multivariate Raftery Copula are found in : - Saali, T., M. Mesfioui, and A. Shabri, 2023: Multivariate Extension of Raftery Copula. Mathematics, 11, 414, https://doi.org/10.3390/math11020414. + [Raftery2023](@cite) Saali, T., M. Mesfioui, and A. Shabri, 2023: Multivariate Extension of Raftery Copula. Mathematics, 11, 414, https://doi.org/10.3390/math11020414. - Nelsen, Roger B. An introduction to copulas. Springer, 2006. Exercise 3.6. + [nelsen2006](@cite) Nelsen, Roger B. An introduction to copulas. Springer, 2006. Exercise 3.6. It has a few special cases: - When θ = 0, it is the IndependentCopula. @@ -41,19 +41,17 @@ struct RafteryCopula{d, P} <: Copula{d} end end end -function _cdf(R::RafteryCopula, u::Vector{T}) where {T} - if length(u) != R.d - throw(ArgumentError("Dimension mismatch")) - end - +Base.eltype(R::RafteryCopula) = eltype(R.θ) + +function _cdf(R::RafteryCopula{d,P}, u::Vector{T}) where {d,P,T} # Order the vector u u_ordered = sort(u) term1 = u_ordered[1] - term2 = (1 - R.θ) * (1 - R.d) / (1 - R.θ - R.d) * prod(u).^(1/(1 - R.θ)) + term2 = (1 - R.θ) * (1 - d) / (1 - R.θ - d) * prod(u).^(1/(1 - R.θ)) term3 = 0.0 - for i in 2:R.d + for i in 2:d prod_prev = prod(u_ordered[1:i-1]) term3 += R.θ * (1 - R.θ) / ((1 - R.θ - i) * (2 - R.θ - i)) * prod_prev^(1/(1 - R.θ)) * u_ordered[i]^((2 - R.θ - i) / (1 - R.θ)) end @@ -62,17 +60,12 @@ function _cdf(R::RafteryCopula, u::Vector{T}) where {T} return cdf_value end - -function Distributions._logpdf(R::RafteryCopula, u::Vector{T}) where {T} - if length(u) != R.d - throw(ArgumentError("Dimension mismatch")) - end - - # Order the vector u +function Distributions._logpdf(R::RafteryCopula{d,P}, u::Vector{T}) where {d,P,T} + # Order the vector u u_ordered = sort(u) - term_denominator = (1 - R.θ)^(R.d - 1) * (1 - R.θ - R.d) - term_numerator = 1 - R.d - R.θ * u_ordered[R.d]^((1 - R.θ - R.d) / (1 - R.θ)) + term_denominator = (1 - R.θ)^(d - 1) * (1 - R.θ - d) + term_numerator = 1 - d - R.θ * u_ordered[d]^((1 - R.θ - d) / (1 - R.θ)) term_product = prod(u)^((R.θ) / (1 - R.θ)) logpdf_value = log(term_numerator) - log(term_denominator) + log(term_product) @@ -88,18 +81,31 @@ function Distributions._rand!(rng::Distributions.AbstractRNG, R::RafteryCopula{d u = rand(rng, dim+1) # Step 2: Generate j from a Bernoulli distribution with parameter θ - j = rand(Bernoulli(R.θ),1) - uj = u[1].^j + j = rand(Distributions.Bernoulli(R.θ), 1) + uj = u[1]^j[1] # Step 3: Calculate v_1, ..., v_d for i in 2:dim+1 - x[i] = u[i]^(1 - R.θ) * uj + x[i-1] = u[i]^(1 - R.θ) * uj end return x end - function ρ(R::RafteryCopula{d,R}) where {d, P} term1 = (d+1)*(2^d-(2-R.θ)^d)-(2^d*R.θ*d) term2 = (2-R.θ)^d*(2^d-d-1) return term1/term2 -end \ No newline at end of file +end +function τ(R::RafteryCopula{d, R}) where {d, P} + term1 = (2^(d-1) * factorial(d)) / ((2^(d-1)-1) * prod(i+1-R.θ for i in 2:d)) + term2 = ((1 - R.θ)^2 * (d^2 - 1)) / ((d-1+R.θ) * (d+1-R.θ) * (2^(d-1)-1)) + term3_sum = 0.0 + for k in 2:d + term3_sum += (R.θ * (1-R.θ) * (2-R.θ)) / (2^k * factorial(k-1) * (1-R.θ-k) * (2-R.θ-k) * prod(i+1-R.θ for i in k:d)) + end + term3 = (2^d * factorial(d)) / (2^(d-1)-1) * term3_sum + + term4 = 1 / (2^(d-1)-1) + + return term1 + term2 - term3 - term4 +end + From 59c18cf069c0e17960638a27efe9f77a1305e640 Mon Sep 17 00:00:00 2001 From: Santymax98 Date: Thu, 30 Nov 2023 10:39:38 -0300 Subject: [PATCH 06/13] modified: test/margins_uniformity.jl --- test/margins_uniformity.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/margins_uniformity.jl b/test/margins_uniformity.jl index 741ab08e..5ae68bf8 100644 --- a/test/margins_uniformity.jl +++ b/test/margins_uniformity.jl @@ -25,6 +25,8 @@ FGMCopula(2,1), MCopula(4), PlackettCopula(2.0), + RafteryCopula(2, 0.2), + RafteryCopula(3, 0.5) # Others ? Yes probably others too ! ) n = 1000 From fd9a3db5f7ef09c079a8b20123ce28c5afd3e5c9 Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:22:41 -0300 Subject: [PATCH 07/13] Update RafteryCopula.jl --- src/MiscellaneousCopulas/RafteryCopula.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MiscellaneousCopulas/RafteryCopula.jl b/src/MiscellaneousCopulas/RafteryCopula.jl index 398a1867..a160100b 100644 --- a/src/MiscellaneousCopulas/RafteryCopula.jl +++ b/src/MiscellaneousCopulas/RafteryCopula.jl @@ -90,12 +90,12 @@ function Distributions._rand!(rng::Distributions.AbstractRNG, R::RafteryCopula{d return x end -function ρ(R::RafteryCopula{d,R}) where {d, P} +function ρ(R::RafteryCopula{d,P}) where {d, P} term1 = (d+1)*(2^d-(2-R.θ)^d)-(2^d*R.θ*d) term2 = (2-R.θ)^d*(2^d-d-1) return term1/term2 end -function τ(R::RafteryCopula{d, R}) where {d, P} +function τ(R::RafteryCopula{d, P}) where {d, P} term1 = (2^(d-1) * factorial(d)) / ((2^(d-1)-1) * prod(i+1-R.θ for i in 2:d)) term2 = ((1 - R.θ)^2 * (d^2 - 1)) / ((d-1+R.θ) * (d+1-R.θ) * (2^(d-1)-1)) term3_sum = 0.0 From e6d9ddbda87aeccc6f9c0297fca7fb7d9a5908bd Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:26:02 -0300 Subject: [PATCH 08/13] Update references.bib --- docs/src/assets/references.bib | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/src/assets/references.bib b/docs/src/assets/references.bib index 69a0d3f7..d160a179 100644 --- a/docs/src/assets/references.bib +++ b/docs/src/assets/references.bib @@ -718,4 +718,15 @@ @article{derumigny2022 pages = {104962}, issn = {0047-259X}, keywords = {Elliptical generator,Identifiability,Meta-elliptical copulas,Recursive algorithm} -} \ No newline at end of file +} + +@article{Raftery2023, + title={Multivariate extension of Raftery copula}, + author={Saali, Tariq and Mesfioui, Mhamed and Shabri, Ani}, + journal={Mathematics}, + volume={11}, + number={2}, + pages={414}, + year={2023}, + publisher={MDPI} +} From ec65d3f6093213a2d7cf02629c25a59de152ff9a Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:33:52 -0300 Subject: [PATCH 09/13] typographical errors --- test/RafteryTest.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/RafteryTest.jl b/test/RafteryTest.jl index 63a567f7..b042aaa6 100644 --- a/test/RafteryTest.jl +++ b/test/RafteryTest.jl @@ -1,7 +1,7 @@ @testitem "RafteryCopula Constructor" begin for d in [2,3,4] - @test isa(RarfteryCopula(d,0.0), IndependentCopula) - @test isa(RarfteryCopula(d,1.0), MCopula) + @test isa(RafteryCopula(d,0.0), IndependentCopula) + @test isa(RafteryCopula(d,1.0), MCopula) end @test_throws ArgumentError RafteryCopula(1,0.5) @test_throws ArgumentError RafteryCopula(3,-1.5) @@ -39,4 +39,4 @@ end F = RafteryCopula(3,0.5) samples = rand(rng,F, n_samples) @test size(samples) == (3, n_samples) -end \ No newline at end of file +end From 0c6c06d8fc9964d4962a26a9f918f09ffcf41090 Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:48:59 -0300 Subject: [PATCH 10/13] Removing dimension 1 test --- test/RafteryTest.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/RafteryTest.jl b/test/RafteryTest.jl index b042aaa6..8519095b 100644 --- a/test/RafteryTest.jl +++ b/test/RafteryTest.jl @@ -3,7 +3,6 @@ @test isa(RafteryCopula(d,0.0), IndependentCopula) @test isa(RafteryCopula(d,1.0), MCopula) end - @test_throws ArgumentError RafteryCopula(1,0.5) @test_throws ArgumentError RafteryCopula(3,-1.5) @test_throws ArgumentError RafteryCopula(2, 2.6) end From c86bfb16bd75dd9ea0731b1c990a613bf6696393 Mon Sep 17 00:00:00 2001 From: Oskar Laverny Date: Thu, 30 Nov 2023 17:54:43 +0100 Subject: [PATCH 11/13] Modify docstring slightly --- src/MiscellaneousCopulas/RafteryCopula.jl | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/MiscellaneousCopulas/RafteryCopula.jl b/src/MiscellaneousCopulas/RafteryCopula.jl index a160100b..3863421c 100644 --- a/src/MiscellaneousCopulas/RafteryCopula.jl +++ b/src/MiscellaneousCopulas/RafteryCopula.jl @@ -2,7 +2,7 @@ RafteryCopula{d, P} Fields: - - θ::Real - parameter + - θ::Real - parameter Constructor @@ -14,18 +14,15 @@ The Multivariate Raftery Copula of dimension d is arameterized by ``\\theta \\in C_{\\theta}(\\mathbf{u}) = u_{(1)} + \\frac{(1 - \\theta)(1 - d)}{1 - \\theta - d} \\left(\\prod_{j=1}^{d} u_j\\right)^{\\frac{1}{1-\\theta}} - \\sum_{i=2}^{d} \\frac{\\theta(1-\\theta)}{(1-\\theta-i)(2-\\theta-i)} \\left(\\prod_{j=1}^{i-1}u_{(j)}\\right)^{\\frac{1}{1-\\theta}}u_{(i)}^{\\frac{2-\\theta-i}{1-\\theta}} ``` - -where ``u_{(1)}, \\ldots , u_{(d)}`` denote the order statistics of ``u_1, \\ldots ,u_d``. - -More details about Multivariate Raftery Copula are found in : - - [Raftery2023](@cite) Saali, T., M. Mesfioui, and A. Shabri, 2023: Multivariate Extension of Raftery Copula. Mathematics, 11, 414, https://doi.org/10.3390/math11020414. - - [nelsen2006](@cite) Nelsen, Roger B. An introduction to copulas. Springer, 2006. Exercise 3.6. +where ``u_{(1)}, \\ldots , u_{(d)}`` denote the order statistics of ``u_1, \\ldots ,u_d``. More details about Multivariate Raftery Copula are found in the references below. It has a few special cases: - When θ = 0, it is the IndependentCopula. - When θ = 1, it is the the Fréchet upper bound + +References: +* [Raftery2023](@cite) Saali, T., M. Mesfioui, and A. Shabri, 2023: Multivariate Extension of Raftery Copula. Mathematics, 11, 414, https://doi.org/10.3390/math11020414. +* [nelsen2006](@cite) Nelsen, Roger B. An introduction to copulas. Springer, 2006. Exercise 3.6. """ struct RafteryCopula{d, P} <: Copula{d} θ::P # Copula parameter From 0ce8dcdb612c9a9909818bc841c0cd669fac3763 Mon Sep 17 00:00:00 2001 From: Oskar Laverny Date: Thu, 30 Nov 2023 18:05:21 +0100 Subject: [PATCH 12/13] errors in the docs --- docs/src/miscellaneous.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/src/miscellaneous.md b/docs/src/miscellaneous.md index 5081209f..27af7f2f 100644 --- a/docs/src/miscellaneous.md +++ b/docs/src/miscellaneous.md @@ -16,14 +16,12 @@ PlackettCopula Farlie-Gumbel-Morgenstern (FGM) copula -# Raftery copula - ```@docs -RafteryCopula +FGMCopula ``` -## Survival Copula +# Raftery copula ```@docs -SurvivalCopula +RafteryCopula ``` From 1920d01255b1f5562915631b520f9c023944b273 Mon Sep 17 00:00:00 2001 From: Santymax98 <132070198+Santymax98@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:12:20 -0300 Subject: [PATCH 13/13] add tests of CDF and PDF RafteryTest.jl --- test/RafteryTest.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/RafteryTest.jl b/test/RafteryTest.jl index 8519095b..b7d98b55 100644 --- a/test/RafteryTest.jl +++ b/test/RafteryTest.jl @@ -17,6 +17,17 @@ end cdf_value = cdf(F, u) @test cdf_value >= 0 && cdf_value <= 1 end + examples = [ + ([0.2, 0.5], [1.199432, 1e-5], 0.8), + ([0.3, 0.8], [0.2817, 1e-5], 0.5), + ([0.1, 0.2, 0.3], [0.08325884, 1e-5], 0.5), + ([0.4, 0.8, 0.2], [0.120415, 1e-5], 0.1), + ] + + for (u, expected, θ) in examples + copula = RafteryCopula(length(u), θ) + @test cdf(copula, u) ≈ expected[1] atol=expected[2] + end end @testset "RafteryCopula PDF" begin @@ -29,8 +40,20 @@ end pdf_value = pdf(F, u) @test pdf_value >= 0 end + examples = [ + ([0.2, 0.5], [0.114055555, 1e-4], 0.8), + ([0.3, 0.8], [0.6325, 1e-4], 0.5), + ([0.1, 0.2, 0.3], [1.9945086, 1e-4], 0.5), + ([0.4, 0.8, 0.2], [0.939229, 1e-4], 0.1), + ] + + for (u, expected, θ) in examples + copula = RafteryCopula(length(u), θ) + @test pdf(copula, u) ≈ expected[1] atol=expected[2] + end end + @testitem "RafteryCopula Sampling" begin using StableRNGs rng = StableRNG(123)