{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import random\n",
    "import matplotlib.pyplot as plt\n",
    "import sys\n",
    "import time\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### load FICO dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "DATA_DIR = ''\n",
    "file_name = ['transrisk_performance_by_race_ssa.csv','transrisk_cdf_by_race_ssa.csv','totals.csv']\n",
    "df_repay = pd.read_csv(DATA_DIR + file_name[0])\n",
    "df_cdf = pd.read_csv(DATA_DIR + file_name[1])\n",
    "df_dm_ratio = pd.read_csv(DATA_DIR + file_name[2])\n",
    "\n",
    "df_repay = df_repay.rename(columns={\"Non- Hispanic white\": \"Caucasian\", \"Black\": \"African-American\", \"Hispanic\":\"Hispanic\", \"Asian\":\"Asian\"})\n",
    "df_cdf = df_cdf.rename(columns={\"Non- Hispanic white\": \"Caucasian\", \"Black\": \"African-American\", \"Hispanic\":\"Hispanic\", \"Asian\":\"Asian\"})\n",
    "df_dm_ratio = df_dm_ratio.rename(columns={\"Non- Hispanic white\": \"Caucasian\", \"Black\": \"African-American\", \"Hispanic\":\"Hispanic\", \"Asian\":\"Asian\"})\n",
    "\n",
    "df_cdf.iloc[:,1:] = df_cdf.iloc[:,1:]/100.0\n",
    "df_repay.iloc[:,1:] = (100-df_repay.iloc[:,1:])/100.0\n",
    "k1_list = np.linspace(1,2,5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### obtain PDF from CDF"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "nrow, ncol = df_cdf.shape\n",
    "df_pdf = df_cdf.copy()\n",
    "for i in range(nrow-1):\n",
    "    indx = i + 1\n",
    "    df_pdf.iloc[i+1,1:] = df_cdf.iloc[i+1,1:]- df_cdf.iloc[i,1:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 75884 characters]\n",
      "text/plain": [
       "<Figure size 700x300 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(7,3))  \n",
    "plt.subplot(1,2,1)\n",
    "plt.plot(df_pdf[\"Score\"]/100,df_pdf['Caucasian'],label='Caucasian')\n",
    "plt.plot(df_pdf[\"Score\"]/100,df_pdf['African-American'],label='African-American')\n",
    "plt.plot(df_pdf[\"Score\"]/100,df_pdf['Hispanic'],label='Hispanic')\n",
    "plt.plot(df_pdf[\"Score\"]/100,df_pdf['Asian'],label='Asian')\n",
    "plt.xlabel('Score')\n",
    "plt.title(\"PDF of scores\")\n",
    "plt.legend()\n",
    "plt.subplot(1,2,2)\n",
    "plt.plot(df_cdf[\"Score\"]/100,df_cdf['Caucasian'],label='Caucasian')\n",
    "plt.plot(df_cdf[\"Score\"]/100,df_cdf['African-American'],label='African-American')\n",
    "plt.plot(df_cdf[\"Score\"]/100,df_cdf['Hispanic'],label='Hispanic')\n",
    "plt.plot(df_cdf[\"Score\"]/100,df_cdf['Asian'],label='Asian')\n",
    "plt.xlabel('Score')\n",
    "plt.title(\"CDF of scores\")\n",
    "#fig.savefig('pdf_cdf.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### repayment probability $P_{Y|X,S}(1|x,s)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 36408 characters]\n",
      "text/plain": [
       "<Figure size 350x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib\n",
    "matplotlib.rcParams.update({'font.size': 10.7})\n",
    "\n",
    "fig = plt.figure(figsize=(3.5,3))  \n",
    "plt.plot(df_repay[\"Score\"]/100,df_repay.iloc[:,1],label='Caucasian')\n",
    "plt.plot(df_repay[\"Score\"]/100,df_repay.iloc[:,2],label='African-American')\n",
    "plt.plot(df_repay[\"Score\"]/100,df_repay.iloc[:,3],label='Hispanic')\n",
    "plt.plot(df_repay[\"Score\"]/100,df_repay.iloc[:,4],label='Asian')\n",
    "plt.title(r\"$P_{Y|X,S}(1|x,s)$\")\n",
    "plt.xlabel('Score')\n",
    "plt.legend()\n",
    "#fig.savefig('repay_prob.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a simulator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Step 1.** Generate simulated data from the joint distributions given above, $P(X=x,Y=y \\mid S= s) = P(Y=y \\mid X=x, S= s)P(X=x\\mid S=s)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(777)\n",
    "# Step 1\n",
    "NUM_SAMPLES = 100000\n",
    "elements = df_pdf[\"Score\"]\n",
    "probabilities_c = df_pdf[\"Caucasian\"]\n",
    "probabilities_aa = df_pdf[\"African-American\"]\n",
    "probabilities_h = df_pdf[\"Hispanic\"]\n",
    "probabilities_a = df_pdf[\"Asian\"]\n",
    "\n",
    "scores_c = np.random.choice(elements, NUM_SAMPLES, p=probabilities_c)\n",
    "scores_aa = np.random.choice(elements, NUM_SAMPLES, p=probabilities_aa)\n",
    "scores_h = np.random.choice(elements, NUM_SAMPLES, p=probabilities_h)\n",
    "scores_a = np.random.choice(elements, NUM_SAMPLES, p=probabilities_a)\n",
    "prob_repay_c = [df_repay.loc[df_repay[\"Score\"]==x][\"Caucasian\"].values[0] for x in scores_c]\n",
    "prob_repay_aa = [df_repay.loc[df_repay[\"Score\"]==x][\"African-American\"].values[0] for x in scores_aa]\n",
    "prob_repay_h = [df_repay.loc[df_repay[\"Score\"]==x][\"Hispanic\"].values[0] for x in scores_h]\n",
    "prob_repay_a = [df_repay.loc[df_repay[\"Score\"]==x][\"Asian\"].values[0] for x in scores_a]\n",
    "\n",
    "repay_c = np.random.binomial(1, prob_repay_c, NUM_SAMPLES)\n",
    "repay_aa = np.random.binomial(1, prob_repay_aa, NUM_SAMPLES)\n",
    "repay_h = np.random.binomial(1, prob_repay_h, NUM_SAMPLES)\n",
    "repay_a = np.random.binomial(1, prob_repay_a, NUM_SAMPLES)\n",
    "\n",
    "scores_c = scores_c/100.0\n",
    "scores_aa = scores_aa/100.0\n",
    "scores_h = scores_h/100.0\n",
    "scores_a = scores_a/100.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Step 2.** Fit beta distributions to the generated data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 61516 characters]\n",
      "text/plain": [
       "<Figure size 1200x250 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from scipy.stats import beta\n",
    "import scipy.stats as ss\n",
    "# Step 2\n",
    "a_c1,b_c1,loc_c1,scale_c1 = beta.fit(scores_c[repay_c==1])\n",
    "a_c0,b_c0,loc_c0,scale_c0 = beta.fit(scores_c[repay_c==0])\n",
    "a_aa0,b_aa0,loc_aa0,scale_aa0 = beta.fit(scores_aa[repay_aa==0])\n",
    "a_aa1,b_aa1,loc_aa1,scale_aa1 = beta.fit(scores_aa[repay_aa==1])\n",
    "\n",
    "a_h0,b_h0,loc_h0,scale_h0 = beta.fit(scores_h[repay_h==0])\n",
    "a_h1,b_h1,loc_h1,scale_h1 = beta.fit(scores_h[repay_h==1])\n",
    "a_a0,b_a0,loc_a0,scale_a0 = beta.fit(scores_a[repay_a==0])\n",
    "a_a1,b_a1,loc_a1,scale_a1 = beta.fit(scores_a[repay_a==1])\n",
    "\n",
    "\n",
    "def plot_beta(x_range, a, b, mu=0, sigma=1, cdf=False, **kwargs):\n",
    "    '''\n",
    "    Plots the f distribution function for a given x range, a and b\n",
    "    If mu and sigma are not provided, standard beta is plotted\n",
    "    If cdf=True cumulative distribution is plotted\n",
    "    Passes any keyword arguments to matplotlib plot function\n",
    "    '''\n",
    "    x = x_range\n",
    "    if cdf:\n",
    "        y = ss.beta.cdf(x, a, b, mu, sigma)\n",
    "    else:\n",
    "        y = ss.beta.pdf(x, a, b, mu, sigma)\n",
    "    plt.plot(x, y, **kwargs)\n",
    "\n",
    "x = np.linspace(0, 1, 5000)\n",
    "fig = plt.figure(figsize=(12, 2.5))\n",
    "plt.subplot(1,4,1)\n",
    "plt.ylim(0.1, 11.6)\n",
    "plt.xlim(0, 1)\n",
    "plot_beta(x, a_c1,b_c1, 0, 1, color='green', lw=2, ls='-')\n",
    "plot_beta(x, a_c0,b_c0, 0, 1, color='red', lw=2, ls='-')\n",
    "plot_beta(x,(a_c0+a_c1)/2,(b_c0+b_c1)/2, 0, 1, color='blue', label = 'Fail to improve', lw=2, ls='-')\n",
    "plt.hist(scores_c[repay_c==1], density=True, color = 'green', bins=100, label='repay',alpha=0.5)\n",
    "plt.hist(scores_c[repay_c==0], density=True, bins=100, color = 'red', label='default',alpha=0.5)\n",
    "plt.title(\"Caucasian\")\n",
    "plt.xlabel('Score')\n",
    "plt.legend()\n",
    "plt.subplot(1,4,2)\n",
    "plt.ylim(0.1, 11.6)\n",
    "plt.xlim(0, 1)\n",
    "plot_beta(x, a_aa1,b_aa1, 0, 1, color='green', lw=2, ls='-')\n",
    "plot_beta(x,a_aa0,b_aa0, 0, 1, color='red', lw=2, ls='-')\n",
    "plot_beta(x,(a_aa0+a_aa1)/2,(b_aa0+b_aa1)/2, 0, 1, color='blue', label = 'Fail to improve', lw=2, ls='-')\n",
    "plt.hist(scores_aa[repay_aa==1], density=True, color = 'green', bins=100, label='repay',alpha=0.5)\n",
    "plt.hist(scores_aa[repay_aa==0], density=True, color = 'red', bins=100, label='default',alpha=0.5)\n",
    "plt.title(\"African-American\")\n",
    "plt.xlabel('Score')\n",
    "plt.legend()\n",
    "plt.subplot(1,4,3)\n",
    "plt.ylim(0.1, 11.6)\n",
    "plt.xlim(0, 1)\n",
    "plot_beta(x, a_h1,b_h1, 0, 1, color='green', lw=2, ls='-')\n",
    "plot_beta(x,a_h0,b_h0, 0, 1, color='red', lw=2, ls='-')\n",
    "plot_beta(x,(a_h0+a_h1)/2,(b_h0+b_h1)/2, 0, 1, color='blue', label = 'Fail to improve', lw=2, ls='-')\n",
    "plt.hist(scores_h[repay_h==1], density=True, bins=100, color = 'green', label='repay',alpha=0.5)\n",
    "plt.hist(scores_h[repay_h==0], density=True, bins=100, color = 'red', label='default',alpha=0.5)\n",
    "plt.title(\"Hispanic\")\n",
    "plt.xlabel('Score')\n",
    "plt.legend()\n",
    "plt.subplot(1,4,4)\n",
    "plt.ylim(0.1, 11.6)\n",
    "plt.xlim(0, 1)\n",
    "plot_beta(x, a_a1,b_a1, 0, 1, color='green', lw=2, ls='-')\n",
    "plot_beta(x,a_a0,b_a0, 0, 1, color='red', lw=2, ls='-')\n",
    "plot_beta(x,(a_a0+a_a1)/2,(b_a0+b_a1)/2, 0, 1, color='blue', label = 'Fail to improve', lw=2, ls='-')\n",
    "plt.hist(scores_a[repay_a==1], density=True, bins=100, color = 'green', label='repay',alpha=0.5)\n",
    "plt.hist(scores_a[repay_a==0], density=True, bins=100, color = 'red', label='default',alpha=0.5)\n",
    "plt.title(\"Asian\")\n",
    "plt.xlabel('Score')\n",
    "plt.legend()\n",
    "fig.savefig('score_pdf.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Assume $$P^I(\\theta) \\sim Beta(\\frac{a_0+a_1}{2}, \\frac{b_0+b_1}{2}, \\mu, \\sigma)$$**\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib.ticker import LogLocator\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "def plot_monotone_1(x_range, a0, b0, a1, b1, mu=0, sigma=1, **kwargs):\n",
    "    '''\n",
    "    Plots the f distribution function for a given x range, a and b\n",
    "    If mu and sigma are not provided, standard beta is plotted\n",
    "    If cdf=True cumulative distribution is plotted\n",
    "    Passes any keyword arguments to matplotlib plot function\n",
    "    '''\n",
    "    x = x_range\n",
    "    y0 = ss.beta.pdf(x, a0, b0, mu, sigma)\n",
    "    y1 = ss.beta.pdf(x, a1, b1, mu, sigma)\n",
    "    ratio_10 = y1/y0\n",
    "    plt.plot(x, ratio_10, **kwargs)\n",
    "    plt.yscale('log')\n",
    "\n",
    "def plot_monotone_2(x_range, a0, b0, a1, b1, mu=0, sigma=1, **kwargs):\n",
    "    '''\n",
    "    Plots the f distribution function for a given x range, a and b\n",
    "    If mu and sigma are not provided, standard beta is plotted\n",
    "    If cdf=True cumulative distribution is plotted\n",
    "    Passes any keyword arguments to matplotlib plot function\n",
    "    '''\n",
    "    x = x_range\n",
    "    yi = ss.beta.pdf(x, (a0+a1)/2, (b0+b1)/2, mu, sigma)\n",
    "    y1 = ss.beta.pdf(x, a1, b1, mu, sigma)\n",
    "    ratio_1i = y1/yi\n",
    "    plt.plot(x, ratio_1i, **kwargs)\n",
    "    plt.yscale('log')   \n",
    "    \n",
    "def plot_monotone_3(x_range, a0, b0, a1, b1, mu=0, sigma=1, **kwargs):\n",
    "    '''\n",
    "    Plots the f distribution function for a given x range, a and b\n",
    "    If mu and sigma are not provided, standard beta is plotted\n",
    "    If cdf=True cumulative distribution is plotted\n",
    "    Passes any keyword arguments to matplotlib plot function\n",
    "    '''\n",
    "    x = x_range\n",
    "    yi = ss.beta.pdf(x, (a0+a1)/2, (b0+b1)/2, mu, sigma)\n",
    "    y0 = ss.beta.pdf(x, a0, b0, mu, sigma)\n",
    "    ratio_i0 = yi/y0\n",
    "    plt.plot(x, ratio_i0, **kwargs)\n",
    "    plt.yscale('log')  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 37336 characters]\n",
      "text/plain": [
       "<Figure size 350x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(3.5, 3))   \n",
    "ax = fig.add_subplot(111)\n",
    "plt.xlim(0, 1)\n",
    "plt.ylim(0.00001, 10**14)\n",
    "plot_monotone_1(x,a_c0,b_c0,a_c1,b_c1, 0, 1, lw=1.5, ls='-',label='Caucasian')\n",
    "plot_monotone_1(x,a_aa0,b_aa0,a_aa1,b_aa1, 0, 1, lw=1.5, ls='-',label='African-American')\n",
    "plot_monotone_1(x,a_h0,b_h0,a_h1,b_h1, 0, 1,  lw=1.5, ls='-',label='Hispanic')\n",
    "plot_monotone_1(x,a_a0,b_a0,a_a1,b_a1, 0, 1, lw=1.5, ls='-',label='Asian')\n",
    "\n",
    "ax.yaxis.set_major_locator(LogLocator(base=10**13))\n",
    "\n",
    "plt.xlabel('Score')\n",
    "plt.title(r'$\\frac{P_{X|Y,S}(x|1,s)}{P_{X|Y,S}(x|0,s)}$')\n",
    "plt.legend()\n",
    "fig.savefig('p10.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 32084 characters]\n",
      "text/plain": [
       "<Figure size 350x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(3.5, 3))   \n",
    "ax = fig.add_subplot(111)\n",
    "plt.xlim(0, 1)\n",
    "plt.ylim(0.00001, 10**14)\n",
    "plot_monotone_2(x,a_c0,b_c0,a_c1,b_c1, 0, 1, lw=1.5, ls='-',label='Caucasian')\n",
    "plot_monotone_2(x,a_aa0,b_aa0,a_aa1,b_aa1, 0, 1, lw=1.5, ls='-',label='African-American')\n",
    "plot_monotone_2(x,a_h0,b_h0,a_h1,b_h1, 0, 1,  lw=1.5, ls='-',label='Hispanic')\n",
    "plot_monotone_2(x,a_a0,b_a0,a_a1,b_a1, 0, 1, lw=1.5, ls='-',label='Asian')\n",
    "\n",
    "ax.yaxis.set_major_locator(LogLocator(base=10**13))\n",
    "\n",
    "plt.xlabel('Score')\n",
    "plt.title(r'$\\frac{P_{X|Y,S}(x|1,s)}{P^I(x)}$')\n",
    "plt.legend()\n",
    "fig.savefig('p1i.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 31996 characters]\n",
      "text/plain": [
       "<Figure size 350x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(3.5, 3))   \n",
    "ax = fig.add_subplot(111)\n",
    "plt.xlim(0, 1)\n",
    "plt.ylim(0.00001, 10**14)\n",
    "plot_monotone_3(x,a_c0,b_c0,a_c1,b_c1, 0, 1, lw=1.5, ls='-',label='Caucasian')\n",
    "plot_monotone_3(x,a_aa0,b_aa0,a_aa1,b_aa1, 0, 1, lw=1.5, ls='-',label='African-American')\n",
    "plot_monotone_3(x,a_h0,b_h0,a_h1,b_h1, 0, 1,  lw=1.5, ls='-',label='Hispanic')\n",
    "plot_monotone_3(x,a_a0,b_a0,a_a1,b_a1, 0, 1, lw=1.5, ls='-',label='Asian')\n",
    "\n",
    "ax.yaxis.set_major_locator(LogLocator(base=10**13))\n",
    "\n",
    "plt.xlabel('Score')\n",
    "plt.title(r'$\\frac{P^I(x)}{P_{X|Y,S}(x|0,s)}$')\n",
    "plt.legend()\n",
    "fig.savefig('pi0.eps', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### demographic parameters\n",
    "\n",
    "The proportion of each demographic group"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.7651094244658052 0.10499462788786937 0.08447143587651611 0.04542451176980931\n"
     ]
    }
   ],
   "source": [
    "# relative sizes\n",
    "total = df_dm_ratio.iloc[0]['Caucasian']+df_dm_ratio.iloc[0]['African-American']+df_dm_ratio.iloc[0]['Hispanic']+df_dm_ratio.iloc[0]['Asian']\n",
    "P_c = df_dm_ratio.iloc[0]['Caucasian']/total\n",
    "P_aa = df_dm_ratio.iloc[0]['African-American']/total\n",
    "P_h = df_dm_ratio.iloc[0]['Hispanic']/total\n",
    "P_a = df_dm_ratio.iloc[0]['Asian']/total\n",
    "print(P_c,P_aa,P_h,P_a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\alpha_s$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.33849 0.75972 0.56977 0.80467\n"
     ]
    }
   ],
   "source": [
    "# repayment rates\n",
    "alpha_aa, alpha_c,alpha_h, alpha_asian = np.sum(repay_aa)/NUM_SAMPLES, np.sum(repay_c)/NUM_SAMPLES,np.sum(repay_h)/NUM_SAMPLES, np.sum(repay_a)/NUM_SAMPLES\n",
    "print(alpha_aa, alpha_c,alpha_h, alpha_asian)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Verification of results\n",
    "\n",
    "We do experiments on:\n",
    "\n",
    "1. Caucasian vs African American\n",
    "\n",
    "2. Asian vs Hispanic\n",
    "\n",
    "### 1. (Non)-strategic optimal threshold and utility"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.stats import norm\n",
    "eps = 0.5\n",
    "u = 1\n",
    "q = 0.3\n",
    "mu_c = 0\n",
    "std_c = 0.25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "# scaled utility function & non-strategic optimal threshold \n",
    "def opt_non_strategic(u,alpha,a0,b0,a1,b1):\n",
    "    theta = np.linspace(0,1,10000)\n",
    "    U = (1 - beta.cdf(theta,a1,b1))*alpha*u - (1-beta.cdf(theta,a0,b0))*(1-alpha)*u  \n",
    "    return U, theta[int(np.argmax(U))]\n",
    "    \n",
    "# one group: measure for calculating unfairness\n",
    "def fair_measure(threshold,a0,b0,a1,b1,alpha,fair_type):\n",
    "    if fair_type == \"eqopt\":\n",
    "        return beta.cdf(threshold, a1, b1, 0, 1)\n",
    "    if fair_type == \"dp\":\n",
    "        return beta.cdf(threshold, a1, b1, 0, 1)*alpha + beta.cdf(threshold, a0, b0, 0, 1)*(1-alpha)\n",
    "\n",
    "# Get manipulation Prob\n",
    "def get_manip_prob(theta, q, eps, ai, bi, a1, b1):\n",
    "    \"\"\"\n",
    "    function to get manip prob under q and eps\n",
    "    \"\"\"\n",
    "    value = (1-q)*(beta.cdf(theta, ai, bi, 0, 1) - beta.cdf(theta, a1, b1, 0, 1)) - eps*(1 - beta.cdf(theta, a1, b1, 0, 1))\n",
    "    return norm.cdf(value, mu_c, std_c) + np.random.normal(0,0.01)   \n",
    "\n",
    "    \n",
    "# Get Phi, which is strategic - non-strategic\n",
    "def get_Phi(u, alpha, theta, q, eps, a0, b0, ai, bi, a1, b1, k1 = 1, k2 = 1, k3 = 1):\n",
    "    \"\"\"\n",
    "    Get Phi, which is strategic - non-strategic\n",
    "    k1, k2, k3 measure our preferences for 3 kinds of behaviors\n",
    "    larger k1 means we prefer improvement\n",
    "    larger k2 means we do not prefer failure of improvement\n",
    "    larger k3 means we do not prefer manipulation\n",
    "    k1=k2=k3=1 is the naive difference\n",
    "    \"\"\"\n",
    "    # manipulation probability\n",
    "    pm = get_manip_prob(theta, q, eps, ai, bi, a1, b1)\n",
    "    # Reverse Benefit\n",
    "    b_1 = k1*(1-pm)*q*(2 - beta.cdf(theta, a0, b0, 0, 1) - beta.cdf(theta, a1, b1, 0, 1))\n",
    "   \n",
    "    # Loss of Failure of Improvement \n",
    "    l_1 = k2*(1-pm)*(1-q)*(beta.cdf(theta, a0, b0, 0, 1) - beta.cdf(theta, ai, bi, 0, 1))\n",
    "    # Loss of manipulation\n",
    "    \n",
    "    l_2 = k3*pm*((1-eps)*(1 - beta.cdf(theta, a1, b1, 0, 1))-(1-beta.cdf(theta, a0, b0, 0, 1)))\n",
    "    \n",
    "    return u*(1-alpha)*(b_1-l_1-l_2)\n",
    "    \n",
    "def get_strat_utility(u, alpha, theta, q, eps, a0, b0, ai, bi, a1, b1, k1 = 1, k2 = 1, k3 = 1):\n",
    "    phi = get_Phi(u, alpha, theta, q, eps, a0, b0, ai, bi, a1, b1, k1, k2, k3)\n",
    "    U = (1 - beta.cdf(theta,a1,b1))*alpha*u - (1 - beta.cdf(theta,a0,b0))*(1-alpha)*u + phi\n",
    "    return U\n",
    "\n",
    "def get_strat_optimal(u, alpha, q, eps, a0, b0, ai, bi, a1, b1, k1=1, k2=1, k3=1):\n",
    "    theta = np.linspace(0,1,10000)\n",
    "    U = get_strat_utility(u = u, alpha = alpha, theta = theta, q = q, eps = eps, a0 = a0, b0 = b0, ai = ai, bi = bi, a1 = a1, b1 = b1, k1 = k1, k2 = k2, k3 = k3)\n",
    "    return U, theta[int(np.argmax(U))]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.2270282886663013 12.34042295503264 2.573294489243673 1.235069039702523\n",
      "1.1773023697275014 15.987695811428672 1.8404787762920995 2.3175916528711307\n",
      "1.2305911110526373 9.019826285914492 2.034470325118397 1.9023299221559975\n",
      "0.891080504465652 4.944756596618568 2.310830113800076 1.3779368618171246\n"
     ]
    }
   ],
   "source": [
    "print(a_c0,b_c0,a_c1,b_c1)\n",
    "print(a_aa0,b_aa0,a_aa1,b_aa1)\n",
    "print(a_h0,b_h0,a_h1,b_h1)\n",
    "print(a_a0,b_a0,a_a1,b_a1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def non_strat_utility(u,alpha,theta,a0,b0,a1,b1):\n",
    "    U = (1 - beta.cdf(theta,a1,b1))*alpha*u - (1-beta.cdf(theta,a0,b0))*(1-alpha)*u  \n",
    "    return U\n",
    "\n",
    "def get_strat_optimal(u, alpha, q, eps, a0, b0, ai, bi, a1, b1, k1=1, k2=1, k3=1):\n",
    "    theta = np.linspace(0,1,10000)\n",
    "    U = get_strat_utility(u = u, alpha = alpha, theta = theta, q = q, eps = eps, a0 = a0, b0 = b0, ai = ai, bi = bi, a1 = a1, b1 = b1, k1 = k1, k2 = k2, k3 = k3)\n",
    "    return theta[int(np.argmax(U))]\n",
    "\n",
    "k1_list = np.linspace(1,2,5)\n",
    "strat_func = np.vectorize(get_strat_optimal, excluded=['u', 'alpha', 'q', 'eps', 'a0', 'b0', 'ai', 'bi', 'a1', 'b1', 'k2', 'k3'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run experiments on deltas having different std, each delta 100 times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "# vars not changed\n",
    "sd = [0.02, 0.05, 0.1]\n",
    "def gen_delta(std, n = 100):\n",
    "    return np.random.normal(0,std,n)\n",
    "uhat_c = opt_non_strategic(u,alpha_c,a_c0,b_c0,a_c1,b_c1)[1]\n",
    "uhat_aa = opt_non_strategic(u,alpha_aa,a_aa0,b_aa0,a_aa1,b_aa1)[1]\n",
    "k1_list = np.linspace(1,2,5)\n",
    "strat_func = np.vectorize(get_strat_optimal, excluded=['u', 'alpha', 'q', 'eps', 'a0', 'b0', 'ai', 'bi', 'a1', 'b1', 'k2', 'k3'])\n",
    "phi_func = np.vectorize(get_Phi, excluded = ['u', 'alpha', 'q', 'eps', 'a0', 'b0', 'ai', 'bi', 'a1', 'b1', 'k1','k2','k3'])\n",
    "nonstrat_func = np.vectorize(non_strat_utility, excluded = ['u','alpha','a0','b0','a1','b1'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Experiments on q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(100,)"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# np.random.rand(2,3).mean(axis = 0)\n",
    "np.zeros([100,5]).mean(axis =1).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "average strategic utility for caucasian when sd = 0.02 and k1 = 1.25 is 0.7027702665355549\n",
      "average Pm for caucasian when sd = 0.02 and k1 = 1 is 0.20928960156793888\n",
      "average Pm for caucasian when sd = 0.02 and k1 = 1.25 is 0.1741165792359906\n",
      "average cdf for caucasian when sd = 0.02 and k1 = 1 is 0.015372887619338938\n",
      "average cdf for caucasian when sd = 0.02 and k1 = 1.25 is 0.01217553498868406\n",
      "average strategic utility for aa when sd = 0.02 and k1 = 1.25 is 0.1999382153444046\n",
      "average Pm for aa when sd = 0.02 and k1 = 1 is 0.27435576029291314\n",
      "average Pm for aa when sd = 0.02 and k1 = 1.25 is 0.21319604200149717\n",
      "average cdf for aa when sd = 0.02 and k1 = 1 is 0.0694211222380866\n",
      "average cdf for aa when sd = 0.02 and k1 = 1.25 is 0.052675486109787915\n",
      "average strategic utility for caucasian when sd = 0.05 and k1 = 1.25 is 0.70286601051157\n",
      "average Pm for caucasian when sd = 0.05 and k1 = 1 is 0.21174524864504465\n",
      "average Pm for caucasian when sd = 0.05 and k1 = 1.25 is 0.17838638303234802\n",
      "average cdf for caucasian when sd = 0.05 and k1 = 1 is 0.015728819156192498\n",
      "average cdf for caucasian when sd = 0.05 and k1 = 1.25 is 0.01268075040699211\n",
      "average strategic utility for aa when sd = 0.05 and k1 = 1.25 is 0.20008584756847336\n",
      "average Pm for aa when sd = 0.05 and k1 = 1 is 0.28315082436055955\n",
      "average Pm for aa when sd = 0.05 and k1 = 1.25 is 0.2230130297400822\n",
      "average cdf for aa when sd = 0.05 and k1 = 1 is 0.0717606193146076\n",
      "average cdf for aa when sd = 0.05 and k1 = 1.25 is 0.05511133810851657\n",
      "average strategic utility for caucasian when sd = 0.1 and k1 = 1.25 is 0.6996205314196636\n",
      "average Pm for caucasian when sd = 0.1 and k1 = 1 is 0.21154870050997066\n",
      "average Pm for caucasian when sd = 0.1 and k1 = 1.25 is 0.17020934253034437\n",
      "average cdf for caucasian when sd = 0.1 and k1 = 1 is 0.01585510860112788\n",
      "average cdf for caucasian when sd = 0.1 and k1 = 1.25 is 0.012201338323441674\n",
      "average strategic utility for aa when sd = 0.1 and k1 = 1.25 is 0.19231826926008785\n",
      "average Pm for aa when sd = 0.1 and k1 = 1 is 0.28406934767025765\n",
      "average Pm for aa when sd = 0.1 and k1 = 1.25 is 0.21969592155847192\n",
      "average cdf for aa when sd = 0.1 and k1 = 1 is 0.07283931698804706\n",
      "average cdf for aa when sd = 0.1 and k1 = 1.25 is 0.05490672376223817\n"
     ]
    }
   ],
   "source": [
    "for i in range(len(sd)):\n",
    "    deltas = gen_delta(sd[i])\n",
    "    \n",
    "    theta_c_list = np.zeros([100,5])\n",
    "    utility_c_list = np.zeros([100,5])\n",
    "    utility_c_non = np.zeros([100,5])\n",
    "    manip_list_c = np.zeros([100,5])\n",
    "    manip_hat_c = np.zeros(100)\n",
    "    cdf_c = np.zeros([100,5])\n",
    "    cdf_c_hat = np.zeros([100,5])\n",
    "\n",
    "    theta_aa_list = np.zeros([100,5])\n",
    "    utility_aa_list = np.zeros([100,5])\n",
    "    utility_aa_non = np.zeros([100,5])\n",
    "    manip_list_aa = np.zeros([100,5])\n",
    "    manip_hat_aa = np.zeros(100)\n",
    "    cdf_aa = np.zeros([100,5])\n",
    "    cdf_aa_hat = np.zeros([100,5])\n",
    "    \n",
    "    for j in range(len(deltas)):\n",
    "        theta_c_list[j] = strat_func(u, alpha_c, q+deltas[j], eps, a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1, k1_list)\n",
    "        utility_c_list[j] = phi_func(u, alpha_c, theta_c_list[j], q, eps, a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1) + nonstrat_func(u, alpha_c, theta_c_list[j], a_c0, b_c0,a_c1, b_c1)\n",
    "        utility_c_non[j] = [get_Phi(u, alpha_c, uhat_c, q, eps, a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1) + non_strat_utility(u, alpha_c, uhat_c, a_c0, b_c0,a_c1, b_c1)]*5\n",
    "        manip_list_c[j] = get_manip_prob(theta_c_list[j],q,eps,(a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1)\n",
    "        cdf_c[j] = np.array([fair_measure(theta, a_c0, b_c0, a_c1, b_c1, alpha_c, 'eqopt') for theta in theta_c_list[j]])\n",
    "        manip_hat_c[j] = get_manip_prob(uhat_c,q,eps,(a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1)\n",
    "        cdf_c_hat[j] = fair_measure(uhat_c, a_c0, b_c0, a_c1, b_c1, alpha_c, 'eqopt')\n",
    "        \n",
    "        theta_aa_list[j] = strat_func(u, alpha_aa, q+deltas[j], eps, a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1, k1_list)\n",
    "        utility_aa_list[j] = phi_func(u, alpha_aa, theta_aa_list[j], q, eps, a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1) + nonstrat_func(u, alpha_aa, theta_aa_list[j], a_aa0, b_aa0,a_aa1, b_aa1)\n",
    "        utility_aa_non[j] = [get_Phi(u, alpha_aa, uhat_aa, q, eps, a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1) + non_strat_utility(u, alpha_aa, uhat_aa, a_aa0, b_aa0,a_aa1, b_aa1)]*5\n",
    "        manip_list_aa[j] = get_manip_prob(theta_aa_list[j],q,eps,(a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1)\n",
    "        cdf_aa[j] = np.array([fair_measure(theta, a_aa0, b_aa0, a_aa1, b_aa1, alpha_aa, 'eqopt') for theta in theta_aa_list[j]])\n",
    "        manip_hat_aa[j] = get_manip_prob(uhat_aa,q,eps,(a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1)\n",
    "        cdf_aa_hat[j] = fair_measure(uhat_aa, a_aa0, b_aa0, a_aa1, b_aa1, alpha_aa, 'eqopt')\n",
    "        \n",
    "    error_c_list = theta_c_list.std(axis = 0)  \n",
    "    theta_c_list = theta_c_list.mean(axis = 0)\n",
    "    error_c_non = np.zeros(5)\n",
    "    utility_c_non = utility_c_non.mean(axis=0)\n",
    "    error_manip_c = manip_list_c.std(axis=0)\n",
    "    manip_list_c = manip_list_c.mean(axis=0)\n",
    "    error_hat_c = np.zeros(5)\n",
    "    manip_hat_c = manip_hat_c.mean()\n",
    "    error_cdf_c_hat = np.zeros(5)\n",
    "    cdf_c_hat = cdf_c_hat.mean(axis=0)\n",
    "    error_cdf_c = cdf_c.std(axis=0)\n",
    "    cdf_c = cdf_c.mean(axis=0)\n",
    "    error_utility_c = utility_c_list.std(axis=0)\n",
    "    utility_c_list = utility_c_list.mean(axis=0)\n",
    "    \n",
    "    error_aa_list = theta_aa_list.std(axis = 0)\n",
    "    theta_aa_list = theta_aa_list.mean(axis = 0)\n",
    "    error_aa_non = np.zeros(5)\n",
    "    utility_aa_non = utility_aa_non.mean(axis=0)\n",
    "    error_manip_aa = manip_list_aa.std(axis=0)\n",
    "    manip_list_aa = manip_list_aa.mean(axis=0)\n",
    "    error_hat_aa = np.zeros(5)\n",
    "    manip_hat_aa = manip_hat_aa.mean()\n",
    "    error_cdf_aa_hat = np.zeros(5)\n",
    "    cdf_aa_hat = cdf_aa_hat.mean(axis=0)\n",
    "    error_cdf_aa = cdf_aa.std(axis=0)\n",
    "    cdf_aa = cdf_aa.mean(axis=0)\n",
    "    error_utility_aa = utility_aa_list.std(axis=0)\n",
    "    utility_aa_list = utility_aa_list.mean(axis=0)\n",
    "    \n",
    "    print(f'average strategic utility for caucasian when sd = {sd[i]} and k1 = 1.25 is {utility_c_list[1]}')\n",
    "    print(f'average Pm for caucasian when sd = {sd[i]} and k1 = 1 is {manip_list_c[0]}')\n",
    "    print(f'average Pm for caucasian when sd = {sd[i]} and k1 = 1.25 is {manip_list_c[1]}')\n",
    "    print(f'average cdf for caucasian when sd = {sd[i]} and k1 = 1 is {cdf_c[0]}')\n",
    "    print(f'average cdf for caucasian when sd = {sd[i]} and k1 = 1.25 is {cdf_c[1]}')\n",
    "    \n",
    "    print(f'average strategic utility for aa when sd = {sd[i]} and k1 = 1.25 is {utility_aa_list[1]}')\n",
    "    print(f'average Pm for aa when sd = {sd[i]} and k1 = 1 is {manip_list_aa[0]}')\n",
    "    print(f'average Pm for aa when sd = {sd[i]} and k1 = 1.25 is {manip_list_aa[1]}')\n",
    "    print(f'average cdf for aa when sd = {sd[i]} and k1 = 1 is {cdf_aa[0]}')\n",
    "    print(f'average cdf for aa when sd = {sd[i]} and k1 = 1.25 is {cdf_aa[1]}') \n",
    "    \n",
    "#     # plot optimal threshold, (non)-strategic utility, and manipulation probability\n",
    "#     x = k1_list\n",
    "#     fig, axes = plt.subplots(1,2)\n",
    "#     fig.set_size_inches(7, 3)\n",
    "#     fig.tight_layout(pad=2.0)\n",
    "#     axes[0].tick_params(axis='both', which='major', labelsize=14)\n",
    "#     axes[1].tick_params(axis='both', which='major', labelsize=14)\n",
    "#     axes[0].errorbar(x,manip_list_c,error_manip_c, marker = '.',label = r'$P_M(\\theta^*(k_1))$',linestyle = 'dashed',color = 'blue')\n",
    "#     axes[0].errorbar(x,utility_c_list,error_utility_c,marker = '.',label = r'strategic utility',linestyle = 'solid',color = 'blue')\n",
    "#     axes[0].errorbar(x,cdf_c,error_cdf_c, marker = '.',label = r'$F_{X|Y,S}(\\theta|1,s)$',linestyle = 'dotted',color = 'green')\n",
    "#     axes[0].errorbar(x, utility_c_non,error_c_non, marker = '.', label = r'non-strategic utility',linestyle = 'solid',color = 'red')\n",
    "#     axes[0].errorbar(x, [manip_hat_c]*5, error_hat_c, marker = '.',label = r'$P_M(\\widehat{\\theta}^*)$',linestyle = 'dashed',color = 'red')\n",
    "#     # axes[0].plot(x, [cdf_c_hat]*5,label = r'$F_{X|Y,S}(\\widehat{theta}^*|1,s)$')\n",
    "#     axes[0].set_xlabel(r'$k_1$ normalized by $u(1-\\alpha)$', fontsize = 12)\n",
    "#     axes[0].set_ylabel(r'value', fontsize = 14)\n",
    "#     # axes[0].legend(fontsize = 7, bbox_to_anchor=(0.6, 0.47))\n",
    "#     axes[0].set_title('Caucasian',fontsize = 14)\n",
    "\n",
    "#     axes[1].errorbar(x,manip_list_aa,error_manip_aa, marker = '.',label = r'$P_M(\\theta^*(k_1))$',linestyle = 'dashed',color = 'blue')\n",
    "#     axes[1].errorbar(x,utility_aa_list,error_utility_aa,marker = '.',label = r'strategic utility',linestyle = 'solid',color = 'blue')\n",
    "#     axes[1].errorbar(x,cdf_aa, error_cdf_aa,marker = '.',label = r'$F_{X|Y,S}(\\theta|1,s)$',linestyle = 'dotted',color = 'green')\n",
    "#     axes[1].errorbar(x, utility_aa_non , error_aa_non, marker = '.',label = r'non-strategic utility',linestyle = 'solid',color = 'red')\n",
    "#     axes[1].errorbar(x, [manip_hat_aa]*5,error_hat_aa, marker = '.',label = r'$P_M(\\widehat{\\theta}^*)$',linestyle = 'dashed',color = 'red')\n",
    "#     # axes[1].plot(x, [cdf_aa_hat]*5,label = r'$F_{X|Y,S}(\\widehat{\\theta}^*|1,s)$')\n",
    "#     axes[1].set_xlabel(r'$k_1$ normalized by $u(1-\\alpha)$', fontsize = 12)\n",
    "#     axes[1].set_ylabel(r'value', fontsize = 14)\n",
    "#     axes[1].legend(fontsize = 8,bbox_to_anchor=(0.3, 0.42))\n",
    "#     axes[1].set_title('African American',fontsize = 14)\n",
    "    \n",
    "#     fig.savefig(f'fairness_caa_noise_{i}.eps')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.042699999999999995"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0.0549-0.0122"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Experiments on eps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "average strategic utility for caucasian when sd = 0.02 and k1 = 1 is 0.7033960555479485\n",
      "average strategic utility for caucasian when sd = 0.02 and k1 = 1.25 is 0.7028649648358696\n",
      "average Pm for caucasian when sd = 0.02 and k1 = 1 is 0.21045742586729232\n",
      "average Pm for caucasian when sd = 0.02 and k1 = 1.25 is 0.17630513721427957\n",
      "average cdf for caucasian when sd = 0.02 and k1 = 1 is 0.015448565068013826\n",
      "average cdf for caucasian when sd = 0.02 and k1 = 1.25 is 0.012334115022699533\n",
      "average strategic utility for aa when sd = 0.02 and k1 = 1 is 0.20317402204422927\n",
      "average strategic utility for aa when sd = 0.02 and k1 = 1.25 is 0.19966753012024424\n",
      "average Pm for aa when sd = 0.02 and k1 = 1 is 0.27773906660190945\n",
      "average Pm for aa when sd = 0.02 and k1 = 1.25 is 0.2173719361787232\n",
      "average cdf for aa when sd = 0.02 and k1 = 1 is 0.06997357260372379\n",
      "average cdf for aa when sd = 0.02 and k1 = 1.25 is 0.05336447965154441\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "average strategic utility for caucasian when sd = 0.05 and k1 = 1 is 0.7025923882951003\n",
      "average strategic utility for caucasian when sd = 0.05 and k1 = 1.25 is 0.7017548789907246\n",
      "average Pm for caucasian when sd = 0.05 and k1 = 1 is 0.212163420993645\n",
      "average Pm for caucasian when sd = 0.05 and k1 = 1.25 is 0.17870375970363328\n",
      "average cdf for caucasian when sd = 0.05 and k1 = 1 is 0.015880381863378406\n",
      "average cdf for caucasian when sd = 0.05 and k1 = 1.25 is 0.012785580490773234\n",
      "average strategic utility for aa when sd = 0.05 and k1 = 1 is 0.20042248395266316\n",
      "average strategic utility for aa when sd = 0.05 and k1 = 1.25 is 0.19621037986317535\n",
      "average Pm for aa when sd = 0.05 and k1 = 1 is 0.28189685738358106\n",
      "average Pm for aa when sd = 0.05 and k1 = 1.25 is 0.22240330387424603\n",
      "average cdf for aa when sd = 0.05 and k1 = 1 is 0.07170623885735589\n",
      "average cdf for aa when sd = 0.05 and k1 = 1.25 is 0.0548949161365869\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "average strategic utility for caucasian when sd = 0.1 and k1 = 1 is 0.7006141127009039\n",
      "average strategic utility for caucasian when sd = 0.1 and k1 = 1.25 is 0.6973057873164786\n",
      "average Pm for caucasian when sd = 0.1 and k1 = 1 is 0.19213568209917625\n",
      "average Pm for caucasian when sd = 0.1 and k1 = 1.25 is 0.15761977273810085\n",
      "average cdf for caucasian when sd = 0.1 and k1 = 1 is 0.014014919721502466\n",
      "average cdf for caucasian when sd = 0.1 and k1 = 1.25 is 0.01093037490093177\n",
      "average strategic utility for aa when sd = 0.1 and k1 = 1 is 0.19466378461479827\n",
      "average strategic utility for aa when sd = 0.1 and k1 = 1.25 is 0.18533533782149192\n",
      "average Pm for aa when sd = 0.1 and k1 = 1 is 0.2512537977277545\n",
      "average Pm for aa when sd = 0.1 and k1 = 1.25 is 0.1941183221523551\n",
      "average cdf for aa when sd = 0.1 and k1 = 1 is 0.0638407754242937\n",
      "average cdf for aa when sd = 0.1 and k1 = 1.25 is 0.04764875921549914\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 49132 characters]\n",
      "text/plain": [
       "<Figure size 700x300 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50916 characters]\n",
      "text/plain": [
       "<Figure size 700x300 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 51264 characters]\n",
      "text/plain": [
       "<Figure size 700x300 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "for i in range(len(sd)):\n",
    "    deltas = gen_delta(sd[i])\n",
    "    \n",
    "    theta_c_list = np.zeros([100,5])\n",
    "    utility_c_list = np.zeros([100,5])\n",
    "    utility_c_non = np.zeros([100,5])\n",
    "    manip_list_c = np.zeros([100,5])\n",
    "    manip_hat_c = np.zeros(100)\n",
    "    cdf_c = np.zeros([100,5])\n",
    "    cdf_c_hat = np.zeros([100,5])\n",
    "\n",
    "    theta_aa_list = np.zeros([100,5])\n",
    "    utility_aa_list = np.zeros([100,5])\n",
    "    utility_aa_non = np.zeros([100,5])\n",
    "    manip_list_aa = np.zeros([100,5])\n",
    "    manip_hat_aa = np.zeros(100)\n",
    "    cdf_aa = np.zeros([100,5])\n",
    "    cdf_aa_hat = np.zeros([100,5])\n",
    "    \n",
    "    for j in range(len(deltas)):\n",
    "        theta_c_list[j] = strat_func(u, alpha_c, q, eps+deltas[j], a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1, k1_list)\n",
    "        utility_c_list[j] = phi_func(u, alpha_c, theta_c_list[j], q, eps, a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1) + nonstrat_func(u, alpha_c, theta_c_list[j], a_c0, b_c0,a_c1, b_c1)\n",
    "        utility_c_non[j] = [get_Phi(u, alpha_c, uhat_c, q, eps, a_c0, b_c0, (a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1) + non_strat_utility(u, alpha_c, uhat_c, a_c0, b_c0,a_c1, b_c1)]*5\n",
    "        manip_list_c[j] = get_manip_prob(theta_c_list[j],q,eps,(a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1)\n",
    "        cdf_c[j] = np.array([fair_measure(theta, a_c0, b_c0, a_c1, b_c1, alpha_c, 'eqopt') for theta in theta_c_list[j]])\n",
    "        manip_hat_c[j] = get_manip_prob(uhat_c,q,eps,(a_c0+a_c1)/2, (b_c0+b_c1)/2, a_c1, b_c1)\n",
    "        cdf_c_hat[j] = fair_measure(uhat_c, a_c0, b_c0, a_c1, b_c1, alpha_c, 'eqopt')\n",
    "        \n",
    "        theta_aa_list[j] = strat_func(u, alpha_aa, q, eps+deltas[j], a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1, k1_list)\n",
    "        utility_aa_list[j] = phi_func(u, alpha_aa, theta_aa_list[j], q, eps, a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1) + nonstrat_func(u, alpha_aa, theta_aa_list[j], a_aa0, b_aa0,a_aa1, b_aa1)\n",
    "        utility_aa_non[j] = [get_Phi(u, alpha_aa, uhat_aa, q, eps, a_aa0, b_aa0, (a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1) + non_strat_utility(u, alpha_aa, uhat_aa, a_aa0, b_aa0,a_aa1, b_aa1)]*5\n",
    "        manip_list_aa[j] = get_manip_prob(theta_aa_list[j],q,eps,(a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1)\n",
    "        cdf_aa[j] = np.array([fair_measure(theta, a_aa0, b_aa0, a_aa1, b_aa1, alpha_aa, 'eqopt') for theta in theta_aa_list[j]])\n",
    "        manip_hat_aa[j] = get_manip_prob(uhat_aa,q,eps,(a_aa0+a_aa1)/2, (b_aa0+b_aa1)/2, a_aa1, b_aa1)\n",
    "        cdf_aa_hat[j] = fair_measure(uhat_aa, a_aa0, b_aa0, a_aa1, b_aa1, alpha_aa, 'eqopt')\n",
    "        \n",
    "    error_c_list = theta_c_list.std(axis = 0)  \n",
    "    theta_c_list = theta_c_list.mean(axis = 0)\n",
    "    error_c_non = np.zeros(5)\n",
    "    utility_c_non = utility_c_non.mean(axis=0)\n",
    "    error_manip_c = manip_list_c.std(axis=0)\n",
    "    manip_list_c = manip_list_c.mean(axis=0)\n",
    "    error_hat_c = np.zeros(5)\n",
    "    manip_hat_c = manip_hat_c.mean()\n",
    "    error_cdf_c_hat = np.zeros(5)\n",
    "    cdf_c_hat = cdf_c_hat.mean(axis=0)\n",
    "    error_cdf_c = cdf_c.std(axis=0)\n",
    "    cdf_c = cdf_c.mean(axis=0)\n",
    "    error_utility_c = utility_c_list.std(axis=0)\n",
    "    utility_c_list = utility_c_list.mean(axis=0)\n",
    "    \n",
    "    error_aa_list = theta_aa_list.std(axis = 0)\n",
    "    theta_aa_list = theta_aa_list.mean(axis = 0)\n",
    "    error_aa_non = np.zeros(5)\n",
    "    utility_aa_non = utility_aa_non.mean(axis=0)\n",
    "    error_manip_aa = manip_list_aa.std(axis=0)\n",
    "    manip_list_aa = manip_list_aa.mean(axis=0)\n",
    "    error_hat_aa = np.zeros(5)\n",
    "    manip_hat_aa = manip_hat_aa.mean()\n",
    "    error_cdf_aa_hat = np.zeros(5)\n",
    "    cdf_aa_hat = cdf_aa_hat.mean(axis=0)\n",
    "    error_cdf_aa = cdf_aa.std(axis=0)\n",
    "    cdf_aa = cdf_aa.mean(axis=0)\n",
    "    error_utility_aa = utility_aa_list.std(axis=0)\n",
    "    utility_aa_list = utility_aa_list.mean(axis=0)\n",
    "    \n",
    "    print(f'average strategic utility for caucasian when sd = {sd[i]} and k1 = 1 is {utility_c_list[0]}')\n",
    "    print(f'average strategic utility for caucasian when sd = {sd[i]} and k1 = 1.25 is {utility_c_list[1]}')\n",
    "    print(f'average Pm for caucasian when sd = {sd[i]} and k1 = 1 is {manip_list_c[0]}')\n",
    "    print(f'average Pm for caucasian when sd = {sd[i]} and k1 = 1.25 is {manip_list_c[1]}')\n",
    "    print(f'average cdf for caucasian when sd = {sd[i]} and k1 = 1 is {cdf_c[0]}')\n",
    "    print(f'average cdf for caucasian when sd = {sd[i]} and k1 = 1.25 is {cdf_c[1]}')\n",
    "    \n",
    "    print(f'average strategic utility for aa when sd = {sd[i]} and k1 = 1 is {utility_aa_list[0]}')\n",
    "    print(f'average strategic utility for aa when sd = {sd[i]} and k1 = 1.25 is {utility_aa_list[1]}')\n",
    "    print(f'average Pm for aa when sd = {sd[i]} and k1 = 1 is {manip_list_aa[0]}')\n",
    "    print(f'average Pm for aa when sd = {sd[i]} and k1 = 1.25 is {manip_list_aa[1]}')\n",
    "    print(f'average cdf for aa when sd = {sd[i]} and k1 = 1 is {cdf_aa[0]}')\n",
    "    print(f'average cdf for aa when sd = {sd[i]} and k1 = 1.25 is {cdf_aa[1]}') \n",
    "    \n",
    "    # plot optimal threshold, (non)-strategic utility, and manipulation probability\n",
    "    x = k1_list\n",
    "    fig, axes = plt.subplots(1,2)\n",
    "    fig.set_size_inches(7, 3)\n",
    "    fig.tight_layout(pad=2.0)\n",
    "    axes[0].tick_params(axis='both', which='major', labelsize=14)\n",
    "    axes[1].tick_params(axis='both', which='major', labelsize=14)\n",
    "    axes[0].errorbar(x,manip_list_c,error_manip_c, marker = '.',label = r'$P_M(\\theta^*(k_1))$',linestyle = 'dashed',color = 'blue')\n",
    "    axes[0].errorbar(x,utility_c_list,error_utility_c,marker = '.',label = r'strategic utility',linestyle = 'solid',color = 'blue')\n",
    "    axes[0].errorbar(x,cdf_c,error_cdf_c, marker = '.',label = r'$F_{X|Y,S}(\\theta|1,s)$',linestyle = 'dotted',color = 'green')\n",
    "    axes[0].errorbar(x, utility_c_non,error_c_non, marker = '.', label = r'non-strategic utility',linestyle = 'solid',color = 'red')\n",
    "    axes[0].errorbar(x, [manip_hat_c]*5, error_hat_c, marker = '.',label = r'$P_M(\\widehat{\\theta}^*)$',linestyle = 'dashed',color = 'red')\n",
    "    # axes[0].plot(x, [cdf_c_hat]*5,label = r'$F_{X|Y,S}(\\widehat{theta}^*|1,s)$')\n",
    "    axes[0].set_xlabel(r'$k_1$ normalized by $u(1-\\alpha)$', fontsize = 12)\n",
    "    axes[0].set_ylabel(r'value', fontsize = 14)\n",
    "    # axes[0].legend(fontsize = 7, bbox_to_anchor=(0.6, 0.47))\n",
    "    axes[0].set_title('Caucasian',fontsize = 14)\n",
    "\n",
    "    axes[1].errorbar(x,manip_list_aa,error_manip_aa, marker = '.',label = r'$P_M(\\theta^*(k_1))$',linestyle = 'dashed',color = 'blue')\n",
    "    axes[1].errorbar(x,utility_aa_list,error_utility_aa,marker = '.',label = r'strategic utility',linestyle = 'solid',color = 'blue')\n",
    "    axes[1].errorbar(x,cdf_aa, error_cdf_aa,marker = '.',label = r'$F_{X|Y,S}(\\theta|1,s)$',linestyle = 'dotted',color = 'green')\n",
    "    axes[1].errorbar(x, utility_aa_non , error_aa_non, marker = '.',label = r'non-strategic utility',linestyle = 'solid',color = 'red')\n",
    "    axes[1].errorbar(x, [manip_hat_aa]*5,error_hat_aa, marker = '.',label = r'$P_M(\\widehat{\\theta}^*)$',linestyle = 'dashed',color = 'red')\n",
    "    # axes[1].plot(x, [cdf_aa_hat]*5,label = r'$F_{X|Y,S}(\\widehat{\\theta}^*|1,s)$')\n",
    "    axes[1].set_xlabel(r'$k_1$ normalized by $u(1-\\alpha)$', fontsize = 12)\n",
    "    axes[1].set_ylabel(r'value', fontsize = 14)\n",
    "    axes[1].legend(fontsize = 8,bbox_to_anchor=(0.3, 0.42))\n",
    "    axes[1].set_title('African American',fontsize = 14)\n",
    "    \n",
    "    fig.savefig(f'fairness_caa_eps_noise_{i}.eps')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0498"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0.0638-0.014"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
