{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0484b0fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normnalized IDIF_mean: [0.   0.   0.   0.   0.55 1.   0.99 0.38 0.18 0.17 0.17 0.11 0.09 0.07\n",
      " 0.05 0.04 0.04 0.04 0.04 0.04 0.04]\n",
      "The shape of IDIF_Brain: (21,)\n"
     ]
    }
   ],
   "source": [
    "#import libraries\n",
    "import tensorflow_probability as tfp\n",
    "import tensorflow as tf\n",
    "from scipy import integrate\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from numpy import asarray\n",
    "tfd = tfp.distributions\n",
    "\n",
    "\n",
    "# The joint_model function takes parameters 1/λz, and  μ_(x), σ_x and sets up a joint distribution using TFP’s \n",
    "# JointDistributionCoroutine. Within this function, an exponential distribution\n",
    "# for the latent variable IDIF-Mean and a normal distribution for the observed variable TAC are defined.\n",
    "\n",
    "def joint_model(alpha_0, mu_g, sigma, n_samples):   \n",
    "                                                    \n",
    "    Z = yield tfd.JointDistributionCoroutine.Root(\n",
    "        tfd.Exponential(\n",
    "            rate=alpha_0,\n",
    "            force_probs_to_zero_outside_support=True,\n",
    "            name=\"mu\",\n",
    "        )\n",
    "    )\n",
    "    X = yield tfd.Normal(\n",
    "        loc=mu_g,\n",
    "        scale=sigma, name=\"X\"\n",
    "    )\n",
    "\n",
    "\n",
    "\n",
    "# Data from Matlab file is loaded into three separate arrays: \n",
    "# mu_prior, mu_gray, and sigma_gray, \n",
    "# which represent prior mean, means of gray matter, and standard deviations of gray matter, respectively. \n",
    "data = pd.read_csv(\"VI_data_pXX.csv\",usecols=range(1,22))\n",
    "\n",
    "#Read prior (IDIF-Mean), mu and sigma (gray_TAC).csv\n",
    "data = np.array(data)\n",
    "mu_prior, mu_gray, sigma_gray = data[0, :], data[1, :], data[2, :]\n",
    "\n",
    "print('Normnalized IDIF_mean:',mu_prior)\n",
    "#print(mu_gray)\n",
    "#print(sigma_gray)\n",
    "\n",
    "\n",
    "#An empty list mu_surrogate is initialized to store the surrogate posterior values.\n",
    "mu_surrogate =list()\n",
    "N=1000\n",
    "\n",
    "# A loop iterates over 21 elements representing time steps, where for each iteration, \n",
    "# corresponding values from mu_prior, mu_gray, and sigma_gray are selected.\n",
    "for t in range(21):\n",
    "    mu_prior_i = mu_prior[t]\n",
    "    mu_gray_i = mu_gray[t]\n",
    "    sigma_gray_i = sigma_gray[t]\n",
    "    \n",
    "    \n",
    "    #A normal distribution is created for the observed data, and N samples are drawn to form the dataset. \n",
    "    #The log-probability function joint_pdf_fixed_to_data is created to calculate the log probability of \n",
    "    #the joint model given the dataset.\n",
    "    \n",
    "    # Sample from the observed data distribution\n",
    "    X=tfp.distributions.Normal(loc=mu_gray_i, scale=sigma_gray_i)\n",
    "    dataset = X.sample(N)\n",
    "    \n",
    "    # Define the joint distribution model\n",
    "    joint_pdf = tfd.JointDistributionCoroutine(\n",
    "        lambda : joint_model(mu_prior_i,mu_gray_i, sigma_gray_i, N)\n",
    "    )\n",
    "\n",
    "    # Define the log-probability function for the dataset\n",
    "    joint_pdf_fixed_to_data = lambda Z: joint_pdf.log_prob(Z, dataset)\n",
    "\n",
    "    #A surrogate posterior distribution is defined as an exponential distribution taking the mu_s, \n",
    "    #which is the prior mean (using IDIF-Mean).\n",
    "    \n",
    "    # Define the surrogate posterior distribution\n",
    "    mu_s = tf.Variable(mu_prior_i, name=\"mu_surrogate\")\n",
    "\n",
    "    surrogate_posterior = tfp.distributions.Exponential(\n",
    "        mu_s,\n",
    "        force_probs_to_zero_outside_support=True,\n",
    "        name=\"surrogate_posterior\"\n",
    "    )\n",
    "\n",
    "    #An Adam optimizer with a learning rate of 0.01 is set up to minimize the loss, \n",
    "    #defined as the negative Evidence Lower Bound (ELBO). \n",
    "    #The optimization loop runs for 1000 steps, updating mu_s\n",
    "    #The surrogate posterior values are stored after completing the loop for all time steps.\n",
    "    \n",
    "    # Fit the surrogate posterior using variational inference\n",
    "    mvn_loss = tfp.vi.fit_surrogate_posterior(target_log_prob_fn=joint_pdf_fixed_to_data,\n",
    "                                   surrogate_posterior=surrogate_posterior,\n",
    "                                   optimizer=tf.optimizers.Adam(0.01), \n",
    "                                   num_steps=1000,sample_size=1)\n",
    "    \n",
    "    \n",
    " \n",
    "    mu_surrogate.append(mu_s)\n",
    "    \n",
    "mu_surr= asarray(mu_surrogate)\n",
    "\n",
    "print('The shape of IDIF_Brain:',mu_surr.shape)\n",
    "np.savetxt(\"VI_data_gen_pXX.csv\", mu_surr, delimiter=',')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c5084cd7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normnalized IDIF_Brain: [[0.    ]\n",
      " [0.    ]\n",
      " [0.    ]\n",
      " [0.581 ]\n",
      " [0.977 ]\n",
      " [1.03  ]\n",
      " [0.442 ]\n",
      " [0.207 ]\n",
      " [0.198 ]\n",
      " [0.142 ]\n",
      " [0.0647]\n",
      " [0.0785]\n",
      " [0.0919]\n",
      " [0.0487]\n",
      " [0.0455]\n",
      " [0.0432]\n",
      " [0.0398]\n",
      " [0.0338]\n",
      " [0.0339]\n",
      " [0.0357]]\n"
     ]
    }
   ],
   "source": [
    "#Load and verify the IDIF_Brain\n",
    "IDIF_Brain = pd.read_csv(\"VI_data_gen_pxx.csv\")\n",
    "\n",
    "IDIF_Brain = np.array(IDIF_Brain)\n",
    "\n",
    "print('Normnalized IDIF_Brain:',IDIF_Brain)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1f7f85ef",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5.3\n"
     ]
    }
   ],
   "source": [
    "#TF version\n",
    "import tensorflow as tf\n",
    "print(tf. __version__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f8a55f2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
