From 0629ba6cdbaccf4a252644a7192b88eba079c19e Mon Sep 17 00:00:00 2001
From: imustitanveer <mustassum.tanveer@gmail.com>
Date: Thu, 14 Mar 2024 20:24:06 +0500
Subject: [PATCH] added Copula Bivariate Joe Functionality

---
 .idea/.gitignore                              |  3 +
 .idea/.name                                   |  1 +
 .idea/Copulas.iml                             | 15 ++++
 .../inspectionProfiles/profiles_settings.xml  |  6 ++
 .idea/misc.xml                                |  6 ++
 .idea/modules.xml                             |  8 ++
 .idea/vcs.xml                                 |  6 ++
 copulas/bivariate/__init__.py                 | 13 ++-
 copulas/bivariate/joe.py                      | 87 +++++++++++++++++++
 9 files changed, 142 insertions(+), 3 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 .idea/.name
 create mode 100644 .idea/Copulas.iml
 create mode 100644 .idea/inspectionProfiles/profiles_settings.xml
 create mode 100644 .idea/misc.xml
 create mode 100644 .idea/modules.xml
 create mode 100644 .idea/vcs.xml
 create mode 100644 copulas/bivariate/joe.py

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000..fb90c2c7
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+joe.py
\ No newline at end of file
diff --git a/.idea/Copulas.iml b/.idea/Copulas.iml
new file mode 100644
index 00000000..3ed51aed
--- /dev/null
+++ b/.idea/Copulas.iml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="PyDocumentationSettings">
+    <option name="format" value="GOOGLE" />
+    <option name="myDocStringFormat" value="Google" />
+  </component>
+  <component name="TestRunnerService">
+    <option name="PROJECT_TEST_RUNNER" value="py.test" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000..105ce2da
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..55d79d65
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+<project version="4">
+  <component name="Black">
+    <option name="sdkName" value="Python 3.11 (pythonProject2)" />
+  </component>
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (pythonProject2)" project-jdk-type="Python SDK" />
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..0cc68576
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/Copulas.iml" filepath="$PROJECT_DIR$/.idea/Copulas.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/copulas/bivariate/__init__.py b/copulas/bivariate/__init__.py
index dafbc821..70a65724 100644
--- a/copulas/bivariate/__init__.py
+++ b/copulas/bivariate/__init__.py
@@ -8,6 +8,7 @@
 from copulas.bivariate.clayton import Clayton
 from copulas.bivariate.frank import Frank
 from copulas.bivariate.gumbel import Gumbel
+from copulas.bivariate.joe import Joe
 from copulas.bivariate.utils import split_matrix
 
 __all__ = (
@@ -16,6 +17,7 @@
     'CopulaTypes',
     'Frank',
     'Gumbel',
+    'Joe'
 )
 
 
@@ -96,8 +98,13 @@ def _compute_candidates(copulas, left_tail, right_tail):
     X_right = np.column_stack((right_tail, right_tail))
 
     for copula in copulas:
-        left.append(copula.cumulative_distribution(X_left) / np.power(left_tail, 2))
-        right.append(_compute_tail(copula.cumulative_distribution(X_right), right_tail))
+        if isinstance(copula, Joe):
+            # Compute dependencies for Joe copula
+            left.append(...)
+            right.append(...)
+        else:
+            left.append(copula.cumulative_distribution(X_left) / np.power(left_tail, 2))
+            right.append(_compute_tail(copula.cumulative_distribution(X_right), right_tail))
 
     return left, right
 
@@ -140,7 +147,7 @@ def select_copula(X):
     copula_candidates = [frank]
 
     # append copulas into the candidate list
-    for copula_class in [Clayton, Gumbel]:
+    for copula_class in [Clayton, Gumbel, Joe]:
         try:
             copula = copula_class()
             copula.tau = frank.tau
diff --git a/copulas/bivariate/joe.py b/copulas/bivariate/joe.py
new file mode 100644
index 00000000..387e7a88
--- /dev/null
+++ b/copulas/bivariate/joe.py
@@ -0,0 +1,87 @@
+import numpy as np
+from copulas.bivariate.base import Bivariate, CopulaTypes
+from copulas.bivariate.utils import split_matrix
+
+class Joe(Bivariate):
+    """Class for Joe copula model."""
+
+    copula_type = CopulaTypes.JOE
+    theta_interval = [0, float('inf')]
+    invalid_thetas = [0]
+
+    def __init__(self, theta=1):
+        """
+        Initialize a Joe copula.
+
+        Parameters:
+        - theta (float): The theta parameter of the Joe copula. Default is 1.
+        """
+        self.theta = theta
+
+    def generator(self, t):
+        """
+        Compute the generator function of the Joe copula.
+
+        The generator function of the Joe copula is defined as:
+
+        .. math:: G(t) = -((1 - t^(-theta))^(-1/theta))
+
+        Parameters:
+        - t (float or np.array): The value(s) at which to evaluate the generator.
+
+        Returns:
+        - float or np.array: The value(s) of the generator function at t.
+        """
+        return -((1 - t ** (-self.theta)) ** (1 / self.theta))
+
+    def pdf(self, X):
+        """
+        Compute the probability density function for the Joe copula.
+
+        The probability density function (PDF) for the Joe copula is given by:
+
+        .. math:: c(u, v) = (theta - 1) * (u^(-theta) + v^(-theta) - 1)^(theta - 2) * u^(-theta - 1) * v^(-theta - 1)
+
+        Parameters:
+        - X (np.array): The input array of shape (n, 2) containing pairs of values (u, v).
+
+        Returns:
+        - np.array: The probability density values for each pair in X.
+        """
+        U, V = split_matrix(X)
+        return (self.theta - 1) * (U ** (-self.theta) + V ** (-self.theta) - 1) ** (self.theta - 2) * U ** (-self.theta - 1) * V ** (-self.theta - 1)
+
+    def cdf(self, X):
+        """
+        Compute the cumulative distribution function for the Joe copula.
+
+        The cumulative distribution function (CDF) for the Joe copula is given by:
+
+        .. math:: C(u, v) = (u^(-theta) + v^(-theta) - 1)^theta
+
+        Parameters:
+        - X (np.array): The input array of shape (n, 2) containing pairs of values (u, v).
+
+        Returns:
+        - np.array: The cumulative distribution values for each pair in X.
+        """
+        U, V = split_matrix(X)
+        return (U ** (-self.theta) + V ** (-self.theta) - 1) ** self.theta
+
+    def percent_point(self, y, V):
+        """
+        Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`.
+
+        The inverse of conditional cumulative distribution :math:`C(u|v)^{-1}` for the Joe copula
+        is given by:
+
+        .. math:: (y^(1/theta) + v^(-theta) - 1)^(-1/theta)
+
+        Parameters:
+        - y (float or np.array): The value(s) of :math:`C(u|v)`.
+        - V (float or np.array): The given value(s) of v.
+
+        Returns:
+        - float or np.array: The inverse of conditional cumulative distribution values.
+        """
+        return (y ** (1 / self.theta) + V ** (-self.theta) - 1) ** (-1 / self.theta)