Commit ac8406db authored by iker_martin's avatar iker_martin
Browse files

Se han anadido ficheros de analisis para los resultados. Es necesario Python3,...

Se han anadido ficheros de analisis para los resultados. Es necesario Python3, numpy, pandas y Jupyter para usarlos.
parent 03f566b9
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import pandas as pd\n",
"from pandas import DataFrame, Series\n",
"import numpy as np\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"from scipy import stats\n",
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"matrixMalEX=\"data_GG.csv\"\n",
"matrixMal=\"data_GM.csv\"\n",
"matrixIt=\"data_L.csv\"\n",
"n_qty=2 #CAMBIAR SEGUN LA CANTIDAD DE NODOS USADOS\n",
"repet = 3 * 2 #CAMBIAR EL PRIMER NUMERO SEGUN NUMERO DE EJECUCIONES POR CONFIG\n",
"\n",
"p_value = 0.05\n",
"values = [2, 4, 8, 16, 32]\n",
"dist_names = ['null', 'BestFit', 'WorstFit']"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def speedUp(arr, seq, df):\n",
" numP = df.loc[arr.index[0]].NP\n",
" return seq[( seq.NP == numP )]['EX'] / arr.mean()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"dfG = pd.read_csv( matrixMalEX )\n",
"\n",
"dfG = dfG.drop(columns=dfG.columns[0])\n",
"dfG['S'] = dfG['N']\n",
"dfG['N'] = dfG['S'] + dfG['%Async']\n",
"dfG['%Async'] = (dfG['%Async'] / dfG['N']) * 100\n",
"\n",
"if(n_qty == 1):\n",
" group = dfG.groupby(['%Async', 'Groups'])['TE']\n",
"else: \n",
" group = dfG.groupby(['Dist', '%Async', 'Groups'])['TE']\n",
"\n",
"#group\n",
"grouped_aggG = group.agg(['mean'])\n",
"grouped_aggG.rename(columns={'mean':'TE',}, inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from natsort import index_natsorted\n",
"grouped_aggG.sort_values(\n",
" by=\"Groups\",\n",
" key=lambda x: np.argsort(index_natsorted(df[\"Groups\"]))\n",
")\n",
"grouped_aggG"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"dfM = pd.read_csv( matrixMal )\n",
"dfM = dfM.drop(columns=dfM.columns[0])\n",
"\n",
"dfM['S'] = dfM['N']\n",
"dfM['N'] = dfM['S'] + dfM['%Async']\n",
"dfM[\"TR\"] = dfM[\"TC\"] + dfM[\"TS\"] + dfM[\"TA\"]\n",
"dfM['%Async'] = (dfM['%Async'] / dfM['N']) * 100\n",
"\n",
"if(n_qty == 1):\n",
" groupM = dfM.groupby(['%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']\n",
"else:\n",
" groupM = dfM.groupby(['Dist', '%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']\n",
"\n",
"#group\n",
"grouped_aggM = groupM.agg(['mean'])\n",
"grouped_aggM.columns = grouped_aggM.columns.get_level_values(0)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: FutureWarning: set_axis currently defaults to operating inplace.\n",
"This will change in a future version of pandas, use inplace=True to avoid this warning.\n",
" app.launch_new_instance()\n"
]
}
],
"source": [
"dfL = pd.read_csv( matrixIt )\n",
"dfL = dfL.drop(columns=dfL.columns[0])\n",
"\n",
"dfL['S'] = dfL['N']\n",
"dfL['N'] = dfL['S'] + dfL['%Async']\n",
"dfL['%Async'] = (dfL['%Async'] / dfL['N']) * 100\n",
"\n",
"if(n_qty == 1):\n",
" groupL = dfL[dfL['NS'] != 0].groupby(['Tt', '%Async', 'NP', 'NS'])['Ti', 'To']\n",
"else:\n",
" groupL = dfL[dfL['NS'] != 0].groupby(['Tt', 'Dist', '%Async', 'NP', 'NS'])['Ti', 'To']\n",
"\n",
"#group\n",
"grouped_aggL = groupL.agg(['mean', 'count'])\n",
"grouped_aggL.columns = grouped_aggL.columns.get_level_values(0)\n",
"grouped_aggL.set_axis(['Ti', 'Iters', 'To', 'Iters2'], axis='columns')\n",
"\n",
"grouped_aggL['Iters'] = np.ceil(grouped_aggL['Iters']/6) # TODO Cambiar a repeticiones realizadas\n",
"grouped_aggL['Iters2'] = np.ceil(grouped_aggL['Iters2']/6)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"grouped_aggL.to_excel(\"resultL.xlsx\") \n",
"grouped_aggM.to_excel(\"resultM.xlsx\") \n",
"grouped_aggG.to_excel(\"resultG.xlsx\") "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>Groups</th>\n",
" <th>Dist</th>\n",
" <th>Matrix</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>TE</th>\n",
" <th>S</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8,32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>31.525710</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8,32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>33.315857</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8,32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>33.347537</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>1000000000</td>\n",
" <td>75.0</td>\n",
" <td>4,32</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>57.219027</td>\n",
" <td>250000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>1000000000</td>\n",
" <td>75.0</td>\n",
" <td>4,32</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>55.469166</td>\n",
" <td>250000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>595</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>4,8</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>73.771357</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>596</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>4,8</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>75.557508</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>597</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16,8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>35.949913</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>598</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16,8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>37.900348</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>599</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16,8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>36.012772</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>600 rows × 9 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async Groups Dist Matrix Time Iters TE \\\n",
"0 1000000000 0.0 8,32 2,2 100000 0.1 1000 31.525710 \n",
"1 1000000000 0.0 8,32 2,2 100000 0.1 1000 33.315857 \n",
"2 1000000000 0.0 8,32 2,2 100000 0.1 1000 33.347537 \n",
"3 1000000000 75.0 4,32 1,1 100000 0.1 1000 57.219027 \n",
"4 1000000000 75.0 4,32 1,1 100000 0.1 1000 55.469166 \n",
".. ... ... ... ... ... ... ... ... \n",
"595 1000000000 50.0 4,8 2,2 100000 0.1 1000 73.771357 \n",
"596 1000000000 50.0 4,8 2,2 100000 0.1 1000 75.557508 \n",
"597 1000000000 50.0 16,8 1,1 100000 0.1 1000 35.949913 \n",
"598 1000000000 50.0 16,8 1,1 100000 0.1 1000 37.900348 \n",
"599 1000000000 50.0 16,8 1,1 100000 0.1 1000 36.012772 \n",
"\n",
" S \n",
"0 1000000000 \n",
"1 1000000000 \n",
"2 1000000000 \n",
"3 250000000 \n",
"4 250000000 \n",
".. ... \n",
"595 500000000 \n",
"596 500000000 \n",
"597 500000000 \n",
"598 500000000 \n",
"599 500000000 \n",
"\n",
"[600 rows x 9 columns]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfG"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>TE</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>Groups</th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1,1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td>16,2</td>\n",
" <td>112.087769</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16,32</td>\n",
" <td>18.394706</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16,4</td>\n",
" <td>61.887052</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16,8</td>\n",
" <td>37.986463</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2,16</td>\n",
" <td>113.187865</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">2,2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>4,8</td>\n",
" <td>74.864688</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8,16</td>\n",
" <td>37.999586</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8,2</td>\n",
" <td>123.584176</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8,32</td>\n",
" <td>31.730297</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8,4</td>\n",
" <td>74.052463</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>200 rows × 1 columns</p>\n",
"</div>"
],
"text/plain": [
" TE\n",
"Dist %Async Groups \n",
"1,1 0.0 16,2 112.087769\n",
" 16,32 18.394706\n",
" 16,4 61.887052\n",
" 16,8 37.986463\n",
" 2,16 113.187865\n",
"... ...\n",
"2,2 100.0 4,8 74.864688\n",
" 8,16 37.999586\n",
" 8,2 123.584176\n",
" 8,32 31.730297\n",
" 8,4 74.052463\n",
"\n",
"[200 rows x 1 columns]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggG"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th>Dist</th>\n",
" <th>Matrix</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>TC</th>\n",
" <th>TS</th>\n",
" <th>TA</th>\n",
" <th>S</th>\n",
" <th>TR</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8</td>\n",
" <td>32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>1.341434</td>\n",
" <td>0.695848</td>\n",
" <td>0.000000</td>\n",
" <td>1000000000</td>\n",
" <td>2.037282</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8</td>\n",
" <td>32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>1.405911</td>\n",
" <td>0.639849</td>\n",
" <td>0.000000</td>\n",
" <td>1000000000</td>\n",
" <td>2.045760</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>8</td>\n",
" <td>32</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>1.346017</td>\n",
" <td>0.747863</td>\n",
" <td>0.000000</td>\n",
" <td>1000000000</td>\n",
" <td>2.093880</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>1000000000</td>\n",
" <td>75.0</td>\n",
" <td>4</td>\n",
" <td>32</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.688062</td>\n",
" <td>0.064900</td>\n",
" <td>0.364941</td>\n",
" <td>250000000</td>\n",
" <td>1.117903</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>1000000000</td>\n",
" <td>75.0</td>\n",
" <td>4</td>\n",
" <td>32</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.702200</td>\n",
" <td>0.068039</td>\n",
" <td>0.412072</td>\n",
" <td>250000000</td>\n",
" <td>1.182311</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>595</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>4</td>\n",
" <td>8</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.390444</td>\n",
" <td>0.142287</td>\n",
" <td>0.338576</td>\n",
" <td>500000000</td>\n",
" <td>0.871307</td>\n",
" </tr>\n",
" <tr>\n",
" <td>596</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>4</td>\n",
" <td>8</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.351690</td>\n",
" <td>0.154699</td>\n",
" <td>0.354917</td>\n",
" <td>500000000</td>\n",
" <td>0.861306</td>\n",
" </tr>\n",
" <tr>\n",
" <td>597</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16</td>\n",
" <td>8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.337472</td>\n",
" <td>0.081077</td>\n",
" <td>0.243481</td>\n",
" <td>500000000</td>\n",
" <td>0.662030</td>\n",
" </tr>\n",
" <tr>\n",
" <td>598</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16</td>\n",
" <td>8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.351262</td>\n",
" <td>0.103176</td>\n",
" <td>0.261565</td>\n",
" <td>500000000</td>\n",
" <td>0.716003</td>\n",
" </tr>\n",
" <tr>\n",
" <td>599</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>16</td>\n",
" <td>8</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.349151</td>\n",
" <td>0.094121</td>\n",
" <td>0.221750</td>\n",
" <td>500000000</td>\n",
" <td>0.665022</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>600 rows × 13 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async NP NS Dist Matrix Time Iters TC TS \\\n",
"0 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.341434 0.695848 \n",
"1 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.405911 0.639849 \n",
"2 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.346017 0.747863 \n",
"3 1000000000 75.0 4 32 1,1 100000 0.1 1000 0.688062 0.064900 \n",
"4 1000000000 75.0 4 32 1,1 100000 0.1 1000 0.702200 0.068039 \n",
".. ... ... .. .. ... ... ... ... ... ... \n",
"595 1000000000 50.0 4 8 2,2 100000 0.1 1000 0.390444 0.142287 \n",
"596 1000000000 50.0 4 8 2,2 100000 0.1 1000 0.351690 0.154699 \n",
"597 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.337472 0.081077 \n",
"598 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.351262 0.103176 \n",
"599 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.349151 0.094121 \n",
"\n",
" TA S TR \n",
"0 0.000000 1000000000 2.037282 \n",
"1 0.000000 1000000000 2.045760 \n",
"2 0.000000 1000000000 2.093880 \n",
"3 0.364941 250000000 1.117903 \n",
"4 0.412072 250000000 1.182311 \n",
".. ... ... ... \n",
"595 0.338576 500000000 0.871307 \n",
"596 0.354917 500000000 0.861306 \n",
"597 0.243481 500000000 0.662030 \n",
"598 0.261565 500000000 0.716003 \n",
"599 0.221750 500000000 0.665022 \n",
"\n",
"[600 rows x 13 columns]"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfM"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>TC</th>\n",
" <th>TS</th>\n",
" <th>TA</th>\n",
" <th>TR</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1,1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"4\" valign=\"top\">2</td>\n",
" <td>4</td>\n",
" <td>0.220380</td>\n",
" <td>0.314893</td>\n",
" <td>0.000000</td>\n",
" <td>0.535273</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.248143</td>\n",
" <td>0.375003</td>\n",
" <td>0.000000</td>\n",
" <td>0.623146</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>0.339042</td>\n",
" <td>0.486650</td>\n",
" <td>0.000000</td>\n",
" <td>0.825692</td>\n",
" </tr>\n",
" <tr>\n",
" <td>32</td>\n",
" <td>0.743840</td>\n",
" <td>0.506385</td>\n",
" <td>0.000000</td>\n",
" <td>1.250225</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" <td>0.197858</td>\n",
" <td>0.311136</td>\n",
" <td>0.000000</td>\n",
" <td>0.508994</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">2,2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>16</td>\n",
" <td>32</td>\n",
" <td>1.358891</td>\n",
" <td>0.000000</td>\n",
" <td>1.419016</td>\n",
" <td>2.777907</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"4\" valign=\"top\">32</td>\n",
" <td>2</td>\n",
" <td>0.591882</td>\n",
" <td>0.000000</td>\n",
" <td>2.477300</td>\n",
" <td>3.069183</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>0.804965</td>\n",
" <td>0.000000</td>\n",
" <td>1.729638</td>\n",
" <td>2.534603</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.935128</td>\n",
" <td>0.000000</td>\n",
" <td>1.520682</td>\n",
" <td>2.455810</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>1.221248</td>\n",
" <td>0.000000</td>\n",
" <td>1.541904</td>\n",
" <td>2.763152</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>200 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" TC TS TA TR\n",
"Dist %Async NP NS \n",
"1,1 0.0 2 4 0.220380 0.314893 0.000000 0.535273\n",
" 8 0.248143 0.375003 0.000000 0.623146\n",
" 16 0.339042 0.486650 0.000000 0.825692\n",
" 32 0.743840 0.506385 0.000000 1.250225\n",
" 4 2 0.197858 0.311136 0.000000 0.508994\n",
"... ... ... ... ...\n",
"2,2 100.0 16 32 1.358891 0.000000 1.419016 2.777907\n",
" 32 2 0.591882 0.000000 2.477300 3.069183\n",
" 4 0.804965 0.000000 1.729638 2.534603\n",
" 8 0.935128 0.000000 1.520682 2.455810\n",
" 16 1.221248 0.000000 1.541904 2.763152\n",
"\n",
"[200 rows x 4 columns]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggM"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>N_par</th>\n",
" <th>NS</th>\n",
" <th>Dist</th>\n",
" <th>Matrix</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>Ti</th>\n",
" <th>Tt</th>\n",
" <th>To</th>\n",
" <th>S</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>32</td>\n",
" <td>8</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.005463</td>\n",
" <td>0.0</td>\n",
" <td>6.0</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>32</td>\n",
" <td>8</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.005350</td>\n",
" <td>0.0</td>\n",
" <td>6.0</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>32</td>\n",
" <td>8</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.005355</td>\n",
" <td>0.0</td>\n",
" <td>6.0</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>32</td>\n",
" <td>8</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.005354</td>\n",
" <td>0.0</td>\n",
" <td>6.0</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>1000000000</td>\n",
" <td>0.0</td>\n",
" <td>32</td>\n",
" <td>8</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.005352</td>\n",
" <td>0.0</td>\n",
" <td>6.0</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1199995</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>8</td>\n",
" <td>16</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.024075</td>\n",
" <td>0.0</td>\n",
" <td>27.0</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1199996</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>8</td>\n",
" <td>16</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.024076</td>\n",
" <td>0.0</td>\n",
" <td>27.0</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1199997</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>8</td>\n",
" <td>16</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.024076</td>\n",
" <td>0.0</td>\n",
" <td>27.0</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1199998</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>8</td>\n",
" <td>16</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.024411</td>\n",
" <td>0.0</td>\n",
" <td>27.0</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1199999</td>\n",
" <td>1000000000</td>\n",
" <td>50.0</td>\n",
" <td>8</td>\n",
" <td>16</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0.1</td>\n",
" <td>1000</td>\n",
" <td>0.024075</td>\n",
" <td>0.0</td>\n",
" <td>27.0</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>1200000 rows × 13 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async NP N_par NS Dist Matrix Time Iters \\\n",
"0 1000000000 0.0 32 8 0 2 100000 0.1 1000 \n",
"1 1000000000 0.0 32 8 0 2 100000 0.1 1000 \n",
"2 1000000000 0.0 32 8 0 2 100000 0.1 1000 \n",
"3 1000000000 0.0 32 8 0 2 100000 0.1 1000 \n",
"4 1000000000 0.0 32 8 0 2 100000 0.1 1000 \n",
"... ... ... .. ... .. ... ... ... ... \n",
"1199995 1000000000 50.0 8 16 0 1 100000 0.1 1000 \n",
"1199996 1000000000 50.0 8 16 0 1 100000 0.1 1000 \n",
"1199997 1000000000 50.0 8 16 0 1 100000 0.1 1000 \n",
"1199998 1000000000 50.0 8 16 0 1 100000 0.1 1000 \n",
"1199999 1000000000 50.0 8 16 0 1 100000 0.1 1000 \n",
"\n",
" Ti Tt To S \n",
"0 0.005463 0.0 6.0 1000000000 \n",
"1 0.005350 0.0 6.0 1000000000 \n",
"2 0.005355 0.0 6.0 1000000000 \n",
"3 0.005354 0.0 6.0 1000000000 \n",
"4 0.005352 0.0 6.0 1000000000 \n",
"... ... ... ... ... \n",
"1199995 0.024075 0.0 27.0 500000000 \n",
"1199996 0.024076 0.0 27.0 500000000 \n",
"1199997 0.024076 0.0 27.0 500000000 \n",
"1199998 0.024411 0.0 27.0 500000000 \n",
"1199999 0.024075 0.0 27.0 500000000 \n",
"\n",
"[1200000 rows x 13 columns]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfL"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>Ti</th>\n",
" <th>Iters</th>\n",
" <th>To</th>\n",
" <th>Iters2</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Tt</th>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"4\" valign=\"top\">2</td>\n",
" <td>4</td>\n",
" <td>0.099861</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.099849</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>0.099860</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>32</td>\n",
" <td>0.099853</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" <td>0.049642</td>\n",
" <td>500.0</td>\n",
" <td>55.666667</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>16</td>\n",
" <td>32</td>\n",
" <td>0.034899</td>\n",
" <td>21.0</td>\n",
" <td>14.000000</td>\n",
" <td>21.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"4\" valign=\"top\">32</td>\n",
" <td>2</td>\n",
" <td>0.012084</td>\n",
" <td>101.0</td>\n",
" <td>7.000000</td>\n",
" <td>101.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>0.015599</td>\n",
" <td>54.0</td>\n",
" <td>7.000000</td>\n",
" <td>54.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.012685</td>\n",
" <td>54.0</td>\n",
" <td>7.000000</td>\n",
" <td>54.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>0.015421</td>\n",
" <td>44.0</td>\n",
" <td>7.000000</td>\n",
" <td>44.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>360 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" Ti Iters To Iters2\n",
"Tt Dist %Async NP NS \n",
"0.0 1 0.0 2 4 0.099861 500.0 112.000000 500.0\n",
" 8 0.099849 500.0 112.000000 500.0\n",
" 16 0.099860 500.0 112.000000 500.0\n",
" 32 0.099853 500.0 112.000000 500.0\n",
" 4 2 0.049642 500.0 55.666667 500.0\n",
"... ... ... ... ...\n",
"1.0 2 100.0 16 32 0.034899 21.0 14.000000 21.0\n",
" 32 2 0.012084 101.0 7.000000 101.0\n",
" 4 0.015599 54.0 7.000000 54.0\n",
" 8 0.012685 54.0 7.000000 54.0\n",
" 16 0.015421 44.0 7.000000 44.0\n",
"\n",
"[360 rows x 4 columns]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggL"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO EJECUCCION\n",
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"EX numC= 4 p = 0.039 Diff = 0.09 Asíncrono\n",
"Para 4 padres\n",
"Para 8 padres\n",
"EX numC= 4 p = 0.0 Diff = 1.411 Síncrono\n",
"Para 16 padres\n",
"EX numC= 2 p = 0.014 Diff = 3.662 Asíncrono\n",
"Para 32 padres\n",
"EX numC= 4 p = 0.002 Diff = 4.589 Asíncrono\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"Para 4 padres\n",
"EX numC= 16 p = 0.046 Diff = 0.304 Síncrono\n",
"EX numC= 32 p = 0.012 Diff = 0.542 Síncrono\n",
"Para 8 padres\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # Remove the CWD from sys.path while we load stuff.\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # This is added back by InteractiveShellApp.init_path()\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Para 16 padres\n",
"EX numC= 2 p = 0.023 Diff = 6.349 Asíncrono\n",
"EX numC= 4 p = 0.0 Diff = 1.799 Asíncrono\n",
"EX numC= 8 p = 0.046 Diff = 0.261 Asíncrono\n",
"Para 32 padres\n",
"EX numC= 2 p = 0.01 Diff = 18.514 Asíncrono\n",
"EX numC= 4 p = 0.0 Diff = 4.454 Asíncrono\n",
"EX numC= 8 p = 0.003 Diff = 1.92 Asíncrono\n"
]
}
],
"source": [
"print(\"TIEMPO EJECUCCION\")\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" if numP != numC:\n",
" group = str(numP) + \",\" + str(numC)\n",
" v1 = dfG[(dfG[\"%Async\"] == 0.0)][(dfG.Groups == group)][(dfG[\"Dist\"] == dist_v)]['TE']\n",
" v2 = dfG[(dfG[\"%Async\"] == 100.0)][(dfG.Groups == group)][(dfG[\"Dist\"] == dist_v)]['TE']\n",
" res = stats.ttest_ind(v1, v2)\n",
" diff = grouped_aggG['TE'].loc[(dist_v, 0.0, group)] - grouped_aggG['TE'].loc[(dist_v, 100.0, group)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" \n",
" if res[1] < p_value:\n",
" print(\"EX numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,3)), mejor)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO MALLEABILITY\n",
"Distribución 1 -------------------------\n",
"Para 2 padres\n",
"TR numC= 8 p = 0.0 Diff = 0.029 Síncrono\n",
"Para 4 padres\n",
"TR numC= 8 p = 0.006 Diff = 0.043 Síncrono\n",
"TR numC= 32 p = 0.025 Diff = 0.052 Síncrono\n",
"Para 8 padres\n",
"TR numC= 4 p = 0.016 Diff = 0.022 Asíncrono\n",
"TR numC= 16 p = 0.009 Diff = 0.031 Síncrono\n",
"TR numC= 32 p = 0.0 Diff = 0.483 Síncrono\n",
"Para 16 padres\n",
"TR numC= 8 p = 0.002 Diff = 0.072 Síncrono\n",
"TR numC= 32 p = 0.019 Diff = 0.549 Síncrono\n",
"Para 32 padres\n",
"TR numC= 4 p = 0.002 Diff = 0.981 Síncrono\n",
"TR numC= 8 p = 0.001 Diff = 0.972 Síncrono\n",
"TR numC= 16 p = 0.001 Diff = 0.831 Síncrono\n",
"Distribución 2 -------------------------\n",
"Para 2 padres\n",
"TR numC= 4 p = 0.0 Diff = 0.069 Síncrono\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" if __name__ == '__main__':\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # Remove the CWD from sys.path while we load stuff.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"TR numC= 8 p = 0.029 Diff = 0.035 Síncrono\n",
"Para 4 padres\n",
"TR numC= 8 p = 0.02 Diff = 0.031 Síncrono\n",
"TR numC= 32 p = 0.009 Diff = 0.601 Síncrono\n",
"Para 8 padres\n",
"TR numC= 16 p = 0.011 Diff = 0.729 Síncrono\n",
"TR numC= 32 p = 0.018 Diff = 0.423 Síncrono\n",
"Para 16 padres\n",
"TR numC= 4 p = 0.001 Diff = 0.884 Síncrono\n",
"TR numC= 32 p = 0.021 Diff = 0.36 Síncrono\n",
"Para 32 padres\n",
"TR numC= 2 p = 0.029 Diff = 1.548 Síncrono\n",
"TR numC= 4 p = 0.008 Diff = 0.84 Síncrono\n",
"TR numC= 8 p = 0.011 Diff = 0.726 Síncrono\n",
"TR numC= 16 p = 0.004 Diff = 0.606 Síncrono\n"
]
}
],
"source": [
"print(\"TIEMPO MALLEABILITY\")\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" if numP != numC:\n",
" v1 = dfM[(dfM[\"%Async\"] == 0.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM[\"Dist\"] == dist_v)]['TS']\n",
" v2 = dfM[(dfM[\"%Async\"] == 100.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM[\"Dist\"] == dist_v)]['TA']\n",
" res = stats.ttest_ind(v1, v2)\n",
" diff = grouped_aggM['TS'].loc[(dist_v, 0.0, numP, numC)] - grouped_aggM['TA'].loc[(dist_v, 100.0, numP, numC)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" if res[1] < p_value:\n",
" print(\"TR numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,3)), mejor)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO Iters\n",
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"Ti numC= 4 p = 0.035 Diff = 0.0001 Síncrono\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" if sys.path[0] == '':\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" del sys.path[0]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ti numC= 8 p = 0.025 Diff = 0.0001 Síncrono\n",
"Ti numC= 16 p = 0.002 Diff = 0.0001 Síncrono\n",
"Ti numC= 32 p = 0.007 Diff = 0.0001 Síncrono\n",
"Para 4 padres\n",
"Ti numC= 16 p = 0.0 Diff = 0.0006 Síncrono\n",
"Para 8 padres\n",
"Ti numC= 4 p = 0.0 Diff = 0.0009 Síncrono\n",
"Ti numC= 32 p = 0.007 Diff = 0.0029 Síncrono\n",
"Para 16 padres\n",
"Ti numC= 32 p = 0.0 Diff = 0.0097 Síncrono\n",
"Para 32 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0029 Síncrono\n",
"Ti numC= 4 p = 0.0 Diff = 0.0056 Síncrono\n",
"Ti numC= 8 p = 0.0 Diff = 0.0055 Síncrono\n",
"Ti numC= 16 p = 0.0 Diff = 0.0053 Síncrono\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"Ti numC= 32 p = 0.024 Diff = 0.0256 Síncrono\n",
"Para 4 padres\n",
"Ti numC= 16 p = 0.0 Diff = 0.0243 Síncrono\n",
"Ti numC= 32 p = 0.0 Diff = 0.0343 Síncrono\n",
"Para 8 padres\n",
"Ti numC= 4 p = 0.036 Diff = 0.0044 Síncrono\n",
"Ti numC= 16 p = 0.0 Diff = 0.008 Síncrono\n",
"Ti numC= 32 p = 0.0 Diff = 0.0225 Síncrono\n",
"Para 16 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0067 Síncrono\n",
"Ti numC= 4 p = 0.0 Diff = 0.0092 Síncrono\n",
"Ti numC= 8 p = 0.0 Diff = 0.0098 Síncrono\n",
"Ti numC= 32 p = 0.0 Diff = 0.0224 Síncrono\n",
"Para 32 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0058 Síncrono\n",
"Ti numC= 4 p = 0.0 Diff = 0.0094 Síncrono\n",
"Ti numC= 8 p = 0.0 Diff = 0.0064 Síncrono\n",
"Ti numC= 16 p = 0.0 Diff = 0.0092 Síncrono\n"
]
}
],
"source": [
"print(\"TIEMPO Iters\")\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" if numP != numC:\n",
" #exp = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == 1)][(dfL[\"%Async\"] == 0.0)][(dfL.NP == numP)][(dfL.NS == numC)]\n",
" #TimeOp = exp['Ti'] \n",
" #print(TimeOp)\n",
" v1 = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']\n",
" v2 = dfL[(dfL[\"Tt\"] == 1)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']\n",
" res = stats.ttest_ind(v1, v2, equal_var = False)\n",
" diff = grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)] - grouped_aggL['Ti'].loc[(1, dist, 100.0, numP, numC)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" if res[1] < p_value:\n",
" #and abs(diff) > grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)]\n",
" print(\"Ti numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,4)), mejor)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"NC=4 Es mejor Asíncrono con una diff de 0.123\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # Remove the CWD from sys.path while we load stuff.\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" \n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" app.launch_new_instance()\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"NC=8 Es mejor Asíncrono con una diff de 0.07\n",
"NC=16 Es mejor Asíncrono con una diff de 0.046\n",
"NC=32 Es mejor Asíncrono con una diff de 0.014\n",
"Para 4 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 0.645\n",
"NC=8 Es mejor Asíncrono con una diff de 0.13\n",
"NC=16 Es mejor Asíncrono con una diff de 0.052\n",
"NC=32 Es mejor Síncrono con una diff de 0.005\n",
"Para 8 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.523\n",
"NC=4 Es mejor Asíncrono con una diff de 0.354\n",
"NC=16 Es mejor Asíncrono con una diff de 0.066\n",
"NC=32 Es mejor Síncrono con una diff de 0.327\n",
"Para 16 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 3.676\n",
"NC=4 Es mejor Asíncrono con una diff de 1.235\n",
"NC=8 Es mejor Asíncrono con una diff de 0.406\n",
"NC=32 Es mejor Síncrono con una diff de 0.304\n",
"Para 32 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 16.171\n",
"NC=4 Es mejor Asíncrono con una diff de 4.551\n",
"NC=8 Es mejor Asíncrono con una diff de 1.599\n",
"NC=16 Es mejor Asíncrono con una diff de 0.12\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"NC=4 Es mejor Asíncrono con una diff de 0.13\n",
"NC=8 Es mejor Asíncrono con una diff de 0.064\n",
"NC=16 Es mejor Asíncrono con una diff de 0.034\n",
"NC=32 Es mejor Síncrono con una diff de 0.151\n",
"Para 4 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 0.637\n",
"NC=8 Es mejor Asíncrono con una diff de 0.142\n",
"NC=16 Es mejor Síncrono con una diff de 0.28\n",
"NC=32 Es mejor Síncrono con una diff de 0.499\n",
"Para 8 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.575\n",
"NC=4 Es mejor Asíncrono con una diff de 0.344\n",
"NC=16 Es mejor Síncrono con una diff de 0.32\n",
"NC=32 Es mejor Síncrono con una diff de 0.278\n",
"Para 16 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 6.404\n",
"NC=4 Es mejor Asíncrono con una diff de 1.803\n",
"NC=8 Es mejor Asíncrono con una diff de 0.308\n",
"NC=32 Es mejor Síncrono con una diff de 0.113\n",
"Para 32 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 18.438\n",
"NC=4 Es mejor Asíncrono con una diff de 4.533\n",
"NC=8 Es mejor Asíncrono con una diff de 1.927\n",
"NC=16 Es mejor Asíncrono con una diff de 0.481\n"
]
}
],
"source": [
"iters = dfM['Iters'].mean()\n",
"resultados = [0,0]\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" if numP != numC:\n",
" Titer = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == dist)][(dfL.NP == numC)]['Ti'].mean() #Tiempo por iteracion\n",
" i=0\n",
" for adr in [0.0, 100.0]:\n",
" \n",
" auxExp = dfM[(dfM[\"Dist\"] == dist_v)][(dfM[\"%Async\"] == adr)][(dfM.NP == numP)][(dfM.NS == numC)]\n",
" Tr = auxExp['TS'].mean() + auxExp['TA'].mean() #Tiempo de redistribucion\n",
" M_it = dfL[(dfL[\"Tt\"] == 1)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == adr)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti'].count()/3 #Iteraciones asincronas\n",
" #No se presupone una diferencia temporal entre iteraciones sincronas y asincronas\n",
" if(M_it > iters):\n",
" M_it = iters\n",
" resultados[i] = (iters - M_it) * Titer + Tr\n",
" i+=1\n",
" #print(M_it)\n",
" #print(Titer)\n",
" #print((iters - M_it) * Titer)\n",
" #print(Tr)\n",
" #print(\"End\")\n",
" \n",
" if resultados[0] > resultados[1]:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" diff = abs(round(resultados[0] - resultados[1], 3))\n",
" print(\"NC=\"+ str(numC) + \" Es mejor \" + mejor + \" con una diff de \"+ str(diff))\n",
" #TODO Comprobar"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>Ti</th>\n",
" <th>Iters</th>\n",
" <th>To</th>\n",
" <th>Iters2</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Tt</th>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"4\" valign=\"top\">2</td>\n",
" <td>4</td>\n",
" <td>0.099861</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.099849</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>0.099860</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>32</td>\n",
" <td>0.099853</td>\n",
" <td>500.0</td>\n",
" <td>112.000000</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2</td>\n",
" <td>0.049642</td>\n",
" <td>500.0</td>\n",
" <td>55.666667</td>\n",
" <td>500.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>16</td>\n",
" <td>32</td>\n",
" <td>0.034899</td>\n",
" <td>21.0</td>\n",
" <td>14.000000</td>\n",
" <td>21.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"4\" valign=\"top\">32</td>\n",
" <td>2</td>\n",
" <td>0.012084</td>\n",
" <td>101.0</td>\n",
" <td>7.000000</td>\n",
" <td>101.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>0.015599</td>\n",
" <td>54.0</td>\n",
" <td>7.000000</td>\n",
" <td>54.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>8</td>\n",
" <td>0.012685</td>\n",
" <td>54.0</td>\n",
" <td>7.000000</td>\n",
" <td>54.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>16</td>\n",
" <td>0.015421</td>\n",
" <td>44.0</td>\n",
" <td>7.000000</td>\n",
" <td>44.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>360 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" Ti Iters To Iters2\n",
"Tt Dist %Async NP NS \n",
"0.0 1 0.0 2 4 0.099861 500.0 112.000000 500.0\n",
" 8 0.099849 500.0 112.000000 500.0\n",
" 16 0.099860 500.0 112.000000 500.0\n",
" 32 0.099853 500.0 112.000000 500.0\n",
" 4 2 0.049642 500.0 55.666667 500.0\n",
"... ... ... ... ...\n",
"1.0 2 100.0 16 32 0.034899 21.0 14.000000 21.0\n",
" 32 2 0.012084 101.0 7.000000 101.0\n",
" 4 0.015599 54.0 7.000000 54.0\n",
" 8 0.012685 54.0 7.000000 54.0\n",
" 16 0.015421 44.0 7.000000 44.0\n",
"\n",
"[360 rows x 4 columns]"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggL"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAqQAAAHhCAYAAAC4O6zrAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdd3xUVd4/8M+ZkkzKpE8aIb0XYqQEFURwizyABaQIimUtq+uioo/ss+pvddVVWVQWXQu6rp3qygoWbFFApEqPgUAgAdIhvc/M+f1x74QhmUxCCgP4eb9eeSWZe+6555575853zj3nXCGlBBERERGRq2hcXQAiIiIi+mVjQEpERERELsWAlIiIiIhcigEpEREREbmUztUFICIiIjoXbd++PVin070JIB1sxOsPVgB7zWbz7UOHDi23X8CAlIiIiMgBnU73ZmhoaIrJZKrSaDSclqiPrFarqKioSC0tLX0TwNX2yxjtExERETmWbjKZahmM9g+NRiNNJlMNlBbn05e5oDxERERE5wNNt8Hoo4+GYPVqo9M0q1cb8eijIf1ZsPOVWp+d4k8GpERERES9lZ3diNmzY7sMSlevNmL27FhkZzeeadYHDx7UZ2dnJ8bGxqbFx8enPfnkk8F9Lq8DU6ZMif73v//tPxB59xQDUiIiIqLemjSpDu++W+AwKLUFo+++W4BJk+rONGu9Xo/nn3/+WEFBwb6tW7f+/K9//St4+/bthn4rezfMZvPZ2hQDUiIiIqI+cRSU9jEYBYCoqKi2UaNGNQKAv7+/NS4urqmoqMitY7opU6ZEz5w5M3Lo0KFJ0dHR6UuWLPEFgP3797sNHTo0KTU1NSU1NTXlq6++8gIAq9WK2bNnR8bFxaVdccUV8ZWVle2D3AcNGpTx0EMPhQ0dOjTprbfe8t+3b5/76NGjE9LS0lKGDh2atGPHDgMAvPXWW/4JCQlpSUlJqcOGDUvqzf7Z4yh7IiIiou7cdttg7N3r6TRNSEgbJk9OgMnUhooKPeLimvHkk+F48knH6dPTG/HWW0d7svn9+/e75ebmeo4ZM6be0fKjR4+6b9myZX9ubq77r371q6RrrrlmT3h4uHn9+vUHPD095Z49e9xvuOGG2L179/783nvv+R08eNB9//79+44dO6bPyMhIu+WWW07Y8jIYDNbt27fvB4BLLrkkcfHixYUZGRkt3377rdfdd98duWnTpgPPPvts2JdffnkgJiamrbKyUtuTfXCGASkRERFRf/DxscBkakNJiRvCwlrh42Ppj2xramo0kydPjnv22WePBgQEWB2lmTJlykmtVouMjIyWwYMHt+zcudOQlJTU+rvf/S4qNzfXQ6PRoLCw0B0Avv/+e+O0adNO6nQ6REdHt11yySWnteDOnj27yrbdHTt2eE+dOjXOtqy1tVUAwLBhw+pnzZoVPWXKlKpZs2ZV9XUfGZASERERdacnLZm22/T33VeCd94x4bHHint7u96mpaVFTJgwIW7q1Kknb7755uqu0gkhOv3/9NNPhwQHB7d99NFHh61WKzw8PIZ2ld6e0Wi0AoDFYoHRaDTn5eXldkzz4YcfFn377bden3zyie9FF12UtnPnzn2hoaG9DsDZh5SIiIior+z7jC5cWNzlQKczYLVaMWPGjKjExMTmxx9/vMxZ2v/85z/+FosF+/btcz969Kh7ZmZmc01NjTYsLKxNq9XilVdeCbRYlHhxzJgxdStWrAgwm80oLCzUb9q0yWEZAwICrBEREa1vvfWWv608P/74owcA7Nu3z33cuHENCxcuLPb39zcXFBR06tt6JhiQEhEREfWFowFMzkbf99BXX33lvWrVqsANGzYYk5OTU5OTk1OXLVvm6yhtfHx8y4gRI5ImTJiQsHDhwkJPT095//33ly9ZsiQwMzMz+cCBAwYPDw8rANx0003VsbGxLUlJSWm/+93vIkeMGNFlK+6SJUsK/v3vfwclJSWlJiQkpH300Ud+APDAAw9EJCYmpiYkJKSNHDmybuTIkU292UcbISUfPkBERETU0a5du45kZmZWOk3U3Wj6fhht350pU6ZET5w4sebWW2/tc1/Os2HXrl1BmZmZ0favsYWUiIiIqLc2b/Z0GmzaWko3b3Y+Qv8Xji2kRERERA70qIWUzhhbSImIiIjonMOAlIiIiIhcigEpEREREbkUA1IiIiKi3tr1aAiOdzOt0/HVRux6NOQslei8xICUiIiIqLeCshuxcXZsl0Hp8dVGbJwdi6Dsxt5uwmw2IyUlJXXs2LHxvS6nEyNGjEhat26dS2cBYEBKRERE1FuDJtXh0ncLHAaltmD00ncLMKj3c5A+9dRTIfHx8X2aeL43zGbzWdsWA1IiIiKivnAUlPZTMHro0CH92rVrfe+4444up58aMWJE0m233TY4KysrOSEhIS0nJ8cTAHJycjyzsrKSU1JSUrOyspJ37drlDgD19fVi4sSJsYmJiakTJkyIbW5ubn+wvaenZ9b9998fPmTIkORvvvnGe/369Z7Dhw9PSktLSxk1alRCYWGhHgCeeuqp4Li4uLTExMTUiRMnxvZ2/2x0fc2AiIiI6IK36bbBqN7r/La2IaQN6yYnwN3UhpYKPbzjmrHnyXDsedJxer/0Rox866izLP/whz8Mnj9//rGamhqts3SNjY2aHTt25H3++efed955Z0x+fv6+zMzM5i1btuTp9XqsWrXK+PDDD0esXbv20IIFC4I9PDysBw4cyN28ebPHZZddlmrLp6mpSZOent60cOHC4paWFjFy5MikTz/99GB4eLj5jTfe8H/ooYcGrVix4siiRYtCCwsL93h4eMjKykqnZesJBqRERERE/UHvY4G7qQ3NJW4whLVC72PpS3ZLlizxDQoKMo8ePbpxzZo1TgdOzZw58yQAjB8/vr6+vl5TWVmpra6u1kyfPj3myJEjBiGEbGtrEwCwYcMG7zlz5pQDQHZ2dlNiYmJ7/1atVotbbrmlCgB2797tnp+f7zFu3LhEALBarTCZTG0AkJSU1HTdddfFXH311dWzZs2q7st+AgxIiYiIiLrXTUsmgFO36ZPuK0HBOyZkPFbcl9v1GzZs8P7qq6/8Bg0a5NvS0qJpaGjQXHPNNTH//e9/D3dMK4To9P+8efMGjRkzpu6rr746tH//frdx48YldZXexs3NzarTKeGhlFLEx8c37dy5M69jupycnPzPP//cuGrVKr/58+eH5+fn79Xr9b3dVfYhJSIiIuoz+z6jQxcWdznQ6Qz885//PF5WVrb7+PHje95+++2CkSNH1jkKRgFgyZIl/gCwdu1ab6PRaAkMDLTU1tZqIyIiWgHg9ddfD7KlHTVqVP37778fAABbt241HDhwwGFXhCFDhjSfPHlS9/XXX3sBQEtLi9i2bZvBYrHg0KFDbpMmTap75ZVXjtXV1Wm761LQHbaQEhEREfWFowFM9gOd+jiwqSf8/f0tWVlZyfX19drFixcfBoB58+aV3n777TGLFi0KHT16dK0t7UMPPVQ+Y8aMmMTExNS0tLTGjIyMBkd5GgwGuXTp0kNz5syJrKur01osFnH33XeXZWRktMycOTOmrq5OK6UUd911V1lQUFCfuicIKWVf1iciIiK6IO3atetIZmZml6PbAXQ/mr6fRts7M2LEiKQFCxYcvfzyy3s91+nZtGvXrqDMzMxo+9d4y56IiIiotyo3ezoNNm0tpZWbXTrx/LmOt+yJiIiIeivzqbJu0wyaVDeQt+y3bNmyf6DyPlvYQkpERERELsWAlIiIiIhcigEpEREREbkUA1IiIiKiXnr020dDVu93Ptfo6v2rjY9++2jI2SrT+YgBKREREVEvZQ/Kbpy9anZsV0Hp6v2rjbNXzY7NHpTdqymZnnjiieD4+Pi0hISEtEmTJsU0NjY6fsRSH4wYMSJp3bp1Lp0FgAEpERERUS9NSppU9+617xY4Ckptwei7175bMCnpzEfZHz58WL948eKQnTt35ubn5++zWCzizTffDOi/0jtnNpvP1qYYkBIRERH1haOgtK/BqI3FYhENDQ2atrY2NDU1aSIiIto6phkxYkTSbbfdNjgrKys5ISEhLScnxxMAcnJyPLOyspJTUlJSs7Kyknft2uUOAPX19WLixImxiYmJqRMmTIhtbm5ub3X19PTMuv/++8OHDBmS/M0333ivX7/ec/jw4UlpaWkpo0aNSigsLNQDwFNPPRUcFxeXlpiYmDpx4sTY3u6fDechJSIiIurGbf+9bfDe8r1Ob2uHeIW0TV4+OcHkaWqraKzQx/nHNT+57snwJ9c96TB9enB641vXvHW0q/xiYmLa/vCHP5TGxMQMcXd3t44ePbp28uTJtY7SNjY2anbs2JH3+eefe995550x+fn5+zIzM5u3bNmSp9frsWrVKuPDDz8csXbt2kMLFiwI9vDwsB44cCB38+bNHpdddlmqLZ+mpiZNenp608KFC4tbWlrEyJEjkz799NOD4eHh5jfeeMP/oYceGrRixYojixYtCi0sLNzj4eEhKysr+/Qce4ABKREREVG/8HH3sZg8TW0l9SVuYd5hrT7uPn16vntFRYX2008/9Tt48OCewMBAy4QJE2JfeeWVgHvuuedkx7QzZ848CQDjx4+vr6+v11RWVmqrq6s106dPjzly5IhBCCHb2toEAGzYsMF7zpw55QCQnZ3dlJiY2N6/VavV4pZbbqkCgN27d7vn5+d7jBs3LhEArFYrTCZTGwAkJSU1XXfddTFXX3119axZs6r7sp8AA1IiIiKibjlrybSx3aa/L/u+knd2vWN67PLHivtyu3716tU+kZGRLeHh4WYAuPbaa6s3btzo7SggFUJ0+n/evHmDxowZU/fVV18d2r9/v9u4ceOSukpv4+bmZtXplPBQSini4+Obdu7cmdcxXU5OTv7nn39uXLVqld/8+fPD8/Pz9+r1+t7uKvuQEhEREfWVfZ/RhVctLO5qoNOZiI6Obv3pp5+86+rqNFarFd9++60xJSWl2VHaJUuW+APA2rVrvY1GoyUwMNBSW1urjYiIaAWA119/PciWdtSoUfXvv/9+AABs3brVcODAAYddEYYMGdJ88uRJ3ddff+0FAC0tLWLbtm0Gi8WCQ4cOuU2aNKnulVdeOVZXV6etqanp0217tpASERER9YGjAUz2A516O7Bp3LhxDZMmTaoaMmRIik6nQ1paWuPcuXMrHKX19/e3ZGVlJdfX12sXL158GADmzZtXevvtt8csWrQodPTo0e19Tx966KHyGTNmxCQmJqampaU1ZmRkNDjK02AwyKVLlx6aM2dOZF1dndZisYi77767LCMjo2XmzJkxdXV1WimluOuuu8qCgoL61D1BSCn7sj5ROyFENIDDAPRSyrM2V4QQQgJIkFIe7EMe+wD8QUr5nYNlVwB4X0oZ0Yt8o3GW6qQ/6sFBnl3Wy9kkhJgF4GYp5W9cWY6eGohj4WRbRwDcLqX8WgjxZwCxUsrbB3q7fTWQ5RZC1AMYIqUsEEK8DeCYlPLR/sjbbhvnxHujr4QQgwGsAzBOSnnY1eU51+zatetIZmZmpbM03Y2m76/R9s6MGDEiacGCBUcvv/zyXs11erbt2rUrKDMzM9r+Nd6yH0BCiO+EEFVCCHdXl8URIcQVQohjri7HuUBKmXa+f7AMBPt6EUI8LoR430Xl+OB8CUZdSUr5t/MhGO2op+VWr6ndppNSekspC/qndF1u40K5ZrwB4I8MRntv8/HNns6CTVtL6ebjm1068fy5jrfsB4jaMjYaQA2AqwGscGV5iFxNCKE7my3n5wOhjCoQUkqrq8vSlZ4ct3Pl2J4r5ThfCCEiAbwrpVzTz/lqpZR9un17Pnlq3FNl3aWZlDSpbqBaRwFgy5Yt+wcq77OFLaQDZzaATQDeBnCz/YKO3/KFELcIITbY/S+FEPcIIfKFEHVCiCeFEHFCiB+FELVCiOVCCDe79BOFEDuFENVCiI1CiCF2y44IIR4SQuwWQtQIIZYJIQxCCC8AnwMIF0LUqz/hQgh3IcRCIUSx+rOwqxZeIYRWCLFACFEphCgAMKHDcl8hxL+EECVCiONCiKeEEJ06PavbbRJCBNi9lqXmq1f/v00I8bPa4rxWCBHVRZl8hRDvCiEqhBCFQohHhRAau+V3qPnUCSFyhRAX29XTr9S/PYQQb6vbygUwvMM2/iSEOGSXx3U9rZMu9v0jtbyHhRBz7JY9rh7rd9Vt7RNCDHOWn926E4QQO9Tz5agQ4nG7ZQYhxPtCiBPqObNVCOHwGcu2ehFCXAXgzwCmq+fKLrv6dniM1fP6ByHEi0KIkwAeV8/jb9VtVwohPhBC+Nltb7AQ4j9qfZwQQrxsl5f9e+RStdw16u9L7ZZ9J5T3zA9qvX0phAiyWz5SfZ9UCyF2CaVLBuy2U6Cud1goXQUc1csIobwfq9V9f1nYvSe7OTbfCSGeFkL8AKARQGw39ei0zjrk3d6KrZap3u7HbDsPujmHOx23LrazUj2PagHcIoTQ2OV7Qj137d/TNwnlPXlCCPGIk3I7PD+FEE9D+ZJv2y/buSGFEH8QQuQDyLd7Ld5uE0FCiK/U/f1eqNcPIUS0mlZnV5aO1+eeXDO6vG4K9U6UEOJBIUS5eoxvtcvfXSjXjCIhRJkQ4jUhhIe6LEgIsUath5NCiPXC7nrWoQ7/IZT3eq0QYrsQYrTdshFCiG3qsjIhxAvqIg2AD2z7L7p/74wSp947R4UQt6ivvy2EeFUI8ZkQogHAWOHkWqyeYxvU/a4SynttvN12brWr8wIhxF12y3pcJ3R+4UEcOLMBfKD+/FZ08YHvxFUAhgIYCeBhAIsBzAIwGEA6gBsAQL04vgXgLgCBAF4H8Ik4PYicpuYXA2AIgFuklA0AxgMoVm9veUspiwE8om7zIgCZAEYA6Krv1R0AJgLIAjAMwPUdlr8DwAwgXk3zGwCdbrep2/0RwBS7l2cCWCmlbBNCXAslGJoMwARgPYAlXZTpJQC+AGIBjIFyHG5V62oqlA/X2QB8oLRcn3CQx18AxKk/v0WHLxQADkH5YPQF8ASA94UQYeqy7uqknXoRXQ1gF4BBAK4EcL8Q4rd2ya4GsBSAH4BPALzcVX4dNKj76QclKL5brUeo++ML5VwKBPB7AE3OMpNSfgHgbwCWqedKprqou2OcDaAAQDCApwEIAM8ACAeQopbhcbU+tADWACgEEA2lTpZ2LIsa5HwKYJFa/hcAfCqECLRLNhPKcQ8G4AbgIXXdQeq6TwEIUF//SAhhEsqXtEUAxkspjQAuBbCziyqxAHgAQBCAS6Acu3u6SOvITQDuBGBU99dZPXZZZ85IKe+1vbcBjAJQBeC/6mJn5zDQ+bg5cg2AlVDOsQ8AzAFwLZT3Xbi6vX8CgBAiFcCr6n6HQzluXfXJdnh+SikfgfLet+3XvXbrXKuWObVjZqpZAJ6Ecrx2quXt1hlcM7q7boaq+zQIwO8A/FMI4a8uew5AorpuvJrm/6nLHgRwDMp1LwTKdbCrgR9b1TwCAHwIYIUQwqAu+weAf0gpfaBc15Y72e2u3juRUBoxXlLLcxFOf3/MhHKuGAFsgJNrsSobwH4ox2Q+gH8J0T4PUTmU66iPus6Lti8CZ1gndB5hQDoAhBCjAEQBWC6l3A7l4j/zDLN5TkpZK6XcB2AvgC+llAVSyhooF4UsNd0dAF6XUm6WUlqklO8AaIFycbRZJKUsllKehBIAXeRku7MA/FVKWS6lrIDyYXVTF2mnAVgopTyq5v2MbYEagI8HcL+UskFKWQ7gRQAzusjrQ5wKsoWa7kN12V0AnpFS/qzejvsbgItEh1ZSNaCZDuD/pJR1UsojAJ63K//tAOZLKbdKxUEpZWEX+/W0lPKklPIolCClnZRyhVqfVinlMiitMiO6qxMHhgMwSSn/KqVsVfu8vdGhjjZIKT9Tb3+9B+XDrltSyu+klHvUMu6GEsCPURe3Qfmgj1fPme1SSodP/nCmh8e4WEr5kpTSLKVsUuv8Kylli3p+vWBXrhFQgpX/VfNrllJuQGcTAORLKd9T810CIA/AJLs0/5ZSHpBSNkH58LWd8zcC+EytU6uU8isA2wD8j7rcCiBdCOEhpSxR33+dqHW2Sd3+EShfBMc4StuFt6WU+9TzOQBO6rGbOuuWEMIEYBWUfoI71DydncNAh+PWRdY/SilXqXk0QXmfPiKlPCalbIESyF2vtr5dD2CNlHKduuwxKHXtSG/Oz2fU92tXZf3UbtuPALhEKIN5utPTa0Z31802dXmblPIzAPUAktRr3R0AHlDLXwfl+jbDbr0wAFHquuuldDwSWUr5vpTyhHrMngfgDiDJLp94IUSQlLJeSrnJyT539d6ZBeBrKeUStSwnpJT2Ael/pZQ/SKX7SRucX4sBoFBK+YZ6bXtH3c8QdV8+lVIeUuv8ewBfQvkCdUZ1QucXBqQD42YoAaRtZN6H6NzK1h37PilNDv73Vv+OAvCgevuiWghRDaVlIdwufand34126zoSDqXFxqawQ14d0x7tkNYmCoAeQIlduV6H8q3bkZVQPiTCAVwO5Rvveru8/mGXz0korUaDOuQRBOUbfcfy29INhvLloDvO9gtCiNniVBeJaigt1kE9WbeDKChdJuyP3Z+hXpRVHY+dQdjdXuyKECJbCJGj3i6rgdLKZCvjewDWAlgqlNuL84XaNeIM9eQYnzaRtBAiWAixVCi3pWsBvG9XrsFQPqS66wPY8RwFTj/OQNfnfBSAqR3qfBSAMKncNZgOpa5KhBCfCiGSHRVACJGo3jYsVffjb3b70RP29eK0HrupM6fU47oSwIdSyqV2rzs7hzuWryf7YNuPj+3y/BlKS3IIOrwv1Lp21NII9O787K689tuuh3IN6eq6Zu9MrhnOrpsnOpzXtnPSBMATwHa7evtCfR0A/g7gIIAv1VvXf+qqAELpEvCzULqxVENpnbQd099BaYXNE0oXiIlO9qWr9053dWF/DLq7Fp+2HSmlbWS4t7ov44UQm9Rb8tVQvjDa9qXHdXK2FDxaEFK5utLpXKOVqyuNBY8WnOmd0l8UBqT9TCh9f6YBGKN+WJVCubWXKYSwtW41QLkI2YT2YZNHobTm+dn9eKqtRt1x9K2yGMoHi02k+pojJVAuUvZp7cvVAiDIrlw+Uso0hwWRshrKt+BpUFqTl9h96z0K4K4O++ghpdzYIZtKKN+eO5b/uF0+cV3sS4/2S22VfQPAvQACpZR+UFqwRXfrOnAUwOEO+2WUUv6Pk3V66kMot/gHSyl9AbxmK6PaqvCElDIVym3piVBup3Wn4/nSk2PccZ1n1NeGSOX24Y04VXdHAUT2IODueI4Cpx9nZ44CeK9DnXtJKZ8FACnlWinlr6G0wORBOdaOvKouT1D34892+9ET9vXSXT06q7PuvASgDna3j3twDncsX0/2wbYf4zvUrUFKeRwd3hdCCE8oraCdM3V+fnZVru7Ka79tbyit0sVQrsVA19fjnl4zzuS6aa8SSgNDml2d+UqlmwXU1sUHpZSxUO4AzBVCXNkxE6H0F50H5frprx7TGpx6z+dLKW+A8iXnOQAr1S4qZ6K7urA/Bt1di7ukdjf7CMACACHqvnyGU/vSozo5m3yyfRrzZufFdhWUVq6uNObNzov1yfbp1ZRMU6dOjQ4ICMhMSEjo9Pn59NNPB0dHR6fHx8en/f73vz/jqQm7s2bNGuPYsWPju0/ZdwxI+9+1UFoFUqHc6rgISr+v9Th1Ud0JYLIQwlMoHe9/14ftvQHg92qLmBBCeAllQEtPngxRBiBQCOFr99oSAI+qfeqCoPRl6mqqn+UA5gghItT+UO3fVKWUJVACzOeFED5CGfAQJ4RwdqvxQyh1NAWnbtcDSjD1f0KINKB9IM3Ujiurt36WA3haCGFUP3jn2pX/TQAPCSGGqnUV3/G2v91+/Z8Qwl8IEQHgj3bLvKBceCvUstwKpXWp2zpxYAuAWiHEPKEMpNIKIdKFEMOdrNNTRgAnpZTNQogRsOsyIoQYK4TIEEoXh1ooHxw9GRFbBiBaqAMIenmMjVBuV1YLpT/n/9ot2wIlcHlWPY8NQojLHOTxGYBEIcRMIYROCDEdyvutJyOF3wcwSQjxW7W+DUIZdBIhlIEzV6sf1C1qObuqFyOUuqtXW1Hv7sG2HepBPTqrsy4JZSDIGAAz5emj+Ls7h3vrNSjvPduAIZMQ4hp12UoAE4UyKMYNwF/RxedPN+dnGZQ+iWfqf+y2/SSAzVLpVlMBJUi6UT0fbsPpQVdPrxlnct1spx6XN6D0kbS1iA8Saj9yoQxYjRdCCCh1YYHjc9IIpQ9yBQCdEOL/Qel/CTWfG4UQJnV7tmeOn+ko+A8A/EoIMU193wUKIRx2/+rBtdgZNyjdDSoAmIUy2Kl9yrczqJOzJmhSUF3yu8kFjoJSWzCa/G5yQdCkoF6Nsr/tttsqP/nkk/yOr69evdr46aef+v3888/7Dh48uO+xxx4rdbT+QGhra+v3PBmQ9r+bofTBKZJSltp+oAxGmaW2/rwIoBXKxfUd9LCDvSNSym1Q+iC9DGUQwUEAt/Rw3TwoF9ICodwuCocy2GMbgN0A9gD4SX3NkTeg3Frbpab7T4fls6FcXHLVsq2E0vLUlU8AJAAok1Lusivnx1C+1S8Vyi3LvVD63DnyRyitHgVQOtZ/CGXQF6SUK6B0uv8QSqvRKigtJR09AeX20mEogcJ7dmXJhdIX6kcoxy8DwA9263ZXJ+3Ui/YkKF9aDkNpVXgTyq22vroHwF+FEHVQPhztBzGEQjkWtVBuq36Pnn1Q2KYuOyGE+En9+0yP8RMALobSevMp7OrHrj7iARRBGbgwvWMGUsoTUFrNHoRy2/dhABPtush0SSp9gq+B0qJZAaXV53+hXAs1ap7FUG7pjkHXA5UeghLk10E55su623Y3nNVjl3XWjRugBG/F4tRI+z/34BzurX9AeQ9/qZ53m6AMXIFU+uL+Acp7rwTKPnY1B7Kz8/MfUPqlVgkhFnWxviMfQhmseBLKYFH72RPugHIOnACQBqD9zssZXDPO5LrZ0Two1+1N6vXta5zq+1d+JskAACAASURBVJmg/l8P5Xi9Ih3PfboWytiCA1CuXc04/Rb6VQD2CeWBAf8AMENK6fDxk12RUhZBuXX+IJR63Annfdq7vBZ3s506KAPklkM5T2ZCOa9selonZ5WjoLQ/glEAGD9+fL3JZOrUlenVV181PfzwwyUeHh4SAAYNGtQpzZo1a4zDhg1L+vWvfx0XFxeXNnPmzEiLRYnfZ82aFZmenp4SHx+f9sADD7R3MVm5cqVPTExM2tChQ5NWrlzZPqPH3Llzw2+44Yaoyy67LGHy5MkxZrMZd911V0R6enpKYmJi6t///vcgACgsLNQPGzYsKTk5OTUhISHtiy++cNZNsB2f1ERERETkgP2TmvJuyxvcsLfB6eT25lqztvlQs0Fv0re1VbTpDXGGZp2PrssWXK90r8bkt5K77bO9f/9+t4kTJybk5+e3D7RMTk5OHT9+fPU333zj4+7uLhcsWHB0zJgxp3ULWLNmjXHKlCkJO3bs2JuYmNh6+eWXJ9xxxx2Vt956a1VZWZk2JCTEYjabcemllya99NJLRRkZGc2xsbEZX3311f60tLSWiRMnxjY1NWlycnIOzp07N3zt2rW+mzdvzvP29pYLFiwIKi8v18+fP7+kqalJDB8+PHnlypWHlixZ4t/c3Cyee+65UrPZjLq6Oo2/v/9pgxj5pCYiIiKiAaLz0Vn0Jn1ba0mrm96kb3MWjPaVxWIRVVVV2p07d+bNnz//6MyZM+Os1s6TV2RkZDSkpqa26nQ6TJs27eT69eu9AeCdd94JSE1NTUlNTU3Nz8837Nq1y7Bz505DRERES0ZGRotGo8GsWbNOG3x41VVXVXt7e0sA+Prrr32WL18emJycnJqVlZVSVVWly83NNYwcObJhyZIlQXPnzg3fsmWLR8dgtCsD9qQmIcRbUG6rlUspO/VPEsqE0/PUf+sB3G1/m5aIiIjoXNGTlkzbbfpB9w0qKXunzBT1WFRxX27XOxMaGtp6/fXXV2s0GowdO7ZRo9HI0tJSXXh4+Gm37oU4fQykEAJ5eXluL7/8csj27dt/NplMlilTpkQ3NzdrHKW35+Xl1R5cSinF888/XzRlypRO07KtW7du/0cffeR7yy23xMyZM6fs3nvv7WpWjXYD2UL6NpR+K105DGCMlHIIlE7miwewLEREREQDxr7PaMLChOKuBjr1l0mTJlV//fXXRgDYvXu3e1tbmyY0NLRTP9I9e/Z45eXluVksFqxcuTJg9OjRdVVVVVoPDw9rQECA5ejRo7rvvvvOFwAuuuii5mPHjrnt27fPHQCWLl3qqM80AODXv/51zauvvmpqaWkRtjLU1tZqDhw44DZo0KC2Bx98sPLGG2+s/Omnn5x2c7AZsBZSKeU6oTzPvavl9lP2bELXT+0gIiIiOmc5GsBkP9CpLwObJk2aFLNp0yZjVVWVLiQkZMif/vSn4gceeKByzpw5ldOnT49OSEhI0+v11sWLFx/WaDq3M1500UX1Dz74YEReXp5HdnZ23U033VSt1WqRnp7emJCQkBYZGdkydOjQegDw9PSUL730UuHEiRPjAwICzNnZ2fU///yzh6NyPfDAA5VHjhxxz8jISJFSioCAgLbPPvvs0Nq1a42LFi0K1el00tPT0/LBBx8c7sl+DuigJjUgXePoln2HdA8BSJZSdnqspLr8TiiP2YOXl9fQ5GSHc1WfNQUVytR1saYzncbtwizHuYB1Qc7w/CCiM1VQ0YClb76MiEHOJg4BWje3oubBGvg+7wu3bLdOyxvWN1ha/tQi+zravjfWrFljfP7550NycnIOns3tdsfRoKYBayHtKSHEWCjzcI7qKo2UcjHUW/rDhg2T27ZtO0ulc2z66z8CAJbddQnLcY5gXZAzPD+I6ExNf/1HGHw9kJqa6jRd0ZoiRH0UBf+x/g6X77XubYl5N+ZY7eZaz7MdkJ5PXBqQCiGGQJl3cbw6tyARERHReSPyYWcP5FMETQqqc0UwOnHixLqJEyeeF0Gwy6Z9EkJEQpng+SYp5QFXlYOIiIiIXGsgp31aAuAKAEFCiGNQnpKhBwAp5WtQnh4TCOAVdYoBs5Ry2ECVh4iIiIjOTQM5yv6GbpbfDsDhICYiIiIi+uXgk5qIiIiIeqmoaD6qqnKcpqmsXG0sKHg05CwV6bzEgJSIiIiol4zG4cjNndZlUNraukmTlzc71scnu9FhAicaGxtFRkZGSlJSUmp8fHzaAw88EG5bdvXVV8dER0enJyQkpE2dOjXaNkF9f1q0aFHg7Nmzux+11Q8YkBIRERH1kr//WKSmLncYlFZV5aCu7n8NycnvFgQFTTrj0e4Gg0Fu2LBh//79+3P37duX+8033/h88803XgAwa9askwUFBXv379+/r7m5WSxcuDCon3apW21tbf2eJwNSIiIioj5wFJRWVeUgN3cajMa/N/cmGAUAjUYDX19fKwC0trYKs9ksbM+anz59eo1Go4FGo8GwYcMajh071mlW/kWLFgVeeeWVcaNHj06Ijo5Of/DBB9tn+f/Vr34Vl5aWlhIfH5+2YMGC9mD2H//4R2B0dHT68OHDkzZu3Ohte33KlCnRt99+e0R2dnbiPffcE1FbW6uZOnVqdHp6ekpKSkrq+++/7wcA27ZtM2RkZKQkJyenJiYmpu7Zs8e9J/vq8onxiYiIiM51+fn3o75+p9M0bm7h2L37t3BzC0Nrawk8PVPQ2Pia2/bti5McpffySm9MTn7rqLM8zWYz0tPTU4uKitxvvvnm8nHjxjXYL29paRHLli0LfOGFFxzms3v3bq89e/bs8/b2tmZlZaVec801NZdffnnjBx98cCQkJMRSX18vsrKyUm+88caqlpYWzbPPPhu+ffv2nwMCAiyXXnppUnp6entXg0OHDhl++OGHAzqdDvfee++gsWPH1q5YseJIZWWldtiwYSlXX3117UsvvWS65557yu6+++6Tzc3Nwmw2O60zG7aQEhEREfUDnc4fbm5haGkpgptbGHQ6x09vOrM8dcjLy8stKira/dNPP3lt3brVYL/85ptvjhw5cmT9VVddVe9o/VGjRtWGhoZavL295YQJE6q+++47bwB47rnnQpKSklKHDh2aUlpaqt+3b59h3bp1XiNHjqwLDw83GwwGOXny5JP2eU2ePLlKp1PaMr/77jufF198MSw5OTl11KhRSS0tLeLgwYNul1xyScPzzz8f9sgjj4Tm5+e7eXt79+gZ9WwhJSIiIupGQsLCbtPYbtNHRT2G4uJXER39Fxw/bmpOT0/f39ftBwUFWUaNGlW3evVq3+HDhzcDwIMPPhhWWVmpW7t27aGu1rPd4rf/f82aNcbvv//euG3btjyj0WgdMWJEUlNTk8ZRenve3t5W299SSqxcufJgZmZmi32aiy++uHn06NENH3/8se/48eMTX3nllSNXX311t10W2EJKRERE1Ee2YDQ1dTliYv7a3qe0tXVTr2Ot4uJiXWVlpRYA6uvrxXfffeeTkpLSDAAvvPBC0Lfffuu7atWqAq1W22UeGzZs8CkrK9PW19eLzz77zG/MmDH11dXVWl9fX4vRaLTu2LHDsGvXLi8AuPzyyxs2bdpkLC0t1ba0tIiPP/64yybesWPH1j7//PMhVqsSo/7www8eAJCbm+uWkpLS8uijj5b/5je/qd65c6dHT/aVLaREREREfWAfjPr7jwVwaqDT7t2TDZWVIcbeDGw6evSo/pZbbomxWCyQUoprrrnm5A033FADAA8//HBUWFhYy7Bhw1IAYOLEiVULFiwo6ZjHsGHD6qdPnx5z5MgRw5QpU05cfvnljU1NTU2LFy82JSYmpsbFxTVnZmY2AEBUVFTbvHnzikeOHJliMpnahgwZ0mixWBw2mT777LPFd955Z2RycnKqlFJERES05OTkHHzvvfcCVqxYEajT6aTJZGp75plninuyrwxIiYiIiHrJUTBq4+8/Fkbj35vz8mbH9mbqp+zs7Kaff/4519Eys9m8vSd5BAUFmd99990i+9c8PDzkunXr8h2lv++++07cd999Jzq+/tFHHx2x/9/b21t++OGHhR3TPfPMM6XPPPNMaU/KZo+37ImIiIh6qa5uq8Ng1MbNbaQ1OfndgtrazZ5nuWjnFbaQEhEREfVSZOTD3aYJCppU19u5SPtizpw5JwB0au08F7GFlIiIiIhcigEpERERkQMSyvRG1H+sVqsAYO34OgNSIiIiIgcqGq04ceIEg9J+YrVaRUVFhS+AvR2XsQ8pERERkQOfHmrB0Kg6VFRU9DqP0tJSncViCeo+5S+CFcBes9l8e8cFDEiJiIiIHGg0AzExMX3KIzU1dY+Uclg/FemCxVv2RERERORSDEiJiIiIyKUYkBIRERGRSzEgJSIiIiKXYkBKRERERC7FgJSIiIiIXIoBKRERERG5FANSIiIiInIpBqRERERE5FIMSImIiIjIpRiQEhEREZFLMSAlIiIiIpdiQEpERERELsWAlIiIiIhcigEpEREREbkUA1IiIiIicikGpERERETkUgxIiYiIiMilGJASERERkUsxICUiIiIil2JASkREREQuxYCUiIiIiFyKASkRERERuRQDUiIiIiJyKQakRERERORSDEiJiIiIyKUYkBIRERGRSzEgJSIiIiKXYkBKRERERC7FgJSIiIiIXIoBKRERERG5FANSIiIiInIpBqRERERE5FIMSImIiIjIpRiQnkeK5hehKqfKaZqqnCoUzS86SyUiIiIi6jsGpD1wrgSCxuFG5E7L7bIsVTlVyJ2WC+Nw44CWg4iIiKg/MSDtgU+b/oadk7c5DQR3Tt6GT5v+NqDleGPjLLT+cZ/DoNQWjLb+cR/e2DhrQMtxLii67nFUPbfYaZqq5xaj6LrHz06B6Jwyf0Eycpbd4zRNzrJ7MH9B8lkqERGd8175H+CLF5yn+eIFJR31uwELSIUQbwkhyoUQe7tYLoQQi4QQB4UQu4UQFw9UWfoqeVIinrhunsOg1BaMPnHdPCRPShzQcgxP+RVurJmD1lvzsG/KPiSvNyPgmBWl75Vi3/X70Hr7z5hZ+0cMT/nVgJbjXGAcGY7cp4K7DEqrnluM3KeCYRwZfpZLRueC4YPHYdqBV7sMSnOW3YNpB17F8MHjznLJiOicFfsroOihroPSL15Qlsde+J+xrqAbwLzfBvAygHe7WD4eQIL6kw3gVfX3OWfsxXOBe4EnMA9/mfwcwm/1RHGS5rRg9C/33qik60BaJSwNFlhqLTDXmWGps8BSZ4G59tTfHf8315lhqbX7u05ZX9RdjA8sXwAAzDBj7AcAYEEe8gAA4tl4LMFa4EVgncc6aD210HhqTv32OP1/jYem2zRaTy00HhqHaTQGDYQQZ/FInOI/706kQgk6U7EY8MtoX2YLRlMfLYf/vDtdUj5yrbHTX8HyZcC0A69i+TIAuKl9mS0YXZ54N8ZOf8VlZSSic8xVc4EvoAalAHDJqWW2YDRygZKO+p2QUg5c5kJEA1gjpUx3sOx1AN9JKZeo/+8HcIWUssRZnsOGDZPbtm0bgNJ2L+enF/DEy+/jz0uew4lILUILJbbFbMKwmEQE6RJOBZT11vaA0lJv7VnmWkBn1EJr1EFr1ELno4XW/n9vLbQ+Omh9tCgo+B4vF3+AcYV3IG1vEOSIaiz2/xfuHDQNsfGXw9pohaXRovxuspz+f6MF1iZrp9dkay/OA4FTQW3HoFV9rWPA2+m1nqQxaCA0jgNfW/C5cjpQPDwEr1XvYTBK7WzB58XiHfiZEvB7v/cYjBKRc2rwOf3EMiAgAsuifuxTMCqE2C6lHDYAJb2guDIgXQPgWSnlBvX/bwDMk1I6jTaNRqMcOnToAJS2Z6rrj6F1px5uFndISFg1FuVHWGHVWNX/rbAK5be0+1/aLZd260iNBVIox6Fj2CU6vGj7U9/oheDyaNQYT8C3LhDlwUdg9mzo8X50Cu8kIKSAkBoIqwYaqWn/W0iNsszJ60J9XWPVnMrHUbpe9hKRsEJqrJBCQgrb38qPkBroWzzR4tYK9zYdToYcQYtHfa+201/tvf2Rz7lUlv7KxxVlaQFQY4mBFkCL5jCiNECAEHAXAvp+Ks95xTU3NS4g3VWgo8/Us1jpPL79xIrc1mhAAqnuhwH3OCAgolc5ff/99wxIe2Agb9l3x9HbxmF0LIS4E8CdAODu7j6QZeqWtzkUNbIGZb5lCKoLRPWgcrR6Np4quLT/dWp37P+SACAFBLTQQgsJfRdpgY5fGKwADI2eCC4fhKOmQtQY6lBvqEdEeTTKTUVoMpx5INZpC5oetuo6zadrQmqgsQtkNWrAqrELbO3TtAfBdmls69iCYKvGCkOrcm74l0Wj3rMGdV7VaPSot9X4gO7TQOfRX/mcS2Xpr3x6kocWgBmAVQKHLcBhyPY13dQfdyHUv5Xf7jj9/wvic37g2h/6yVks4IBt6lw8U6TDPy9Y/bKPQhllowFgMfY6GKWec2VAegzAYLv/IwAUO0oopVwMYDGg3LL/7rvvBrxwjtj6jD4+ex6ShoSgco8Giz7+ABe9Mwz+Y/3PWhlyp+Wi9S/7MN48F6nyOpS3rcIizzlweykNqf9OPWtlOVdUPbcYm/4ag9ysaozY7gGfVAtqDwbAUm6BPkgP0/UmBM8Ihu9o3y5v/dOFK2fZPZi9KxJhwh2H3Ofi8chrETZiFkrqSlBSr/7U2f1urOiUh4BAkGcQwoxhCPMOO/Xb/m/1t4fewwV7SUT96osXMH1TK2D1xbKIPwCRV/e676irxlqcb1wZkH4C4F4hxFIog5lquus/6kr2A5hih45Co+4G/OXeH9sHOl30n4EPSu2ndprW+Htc4vM3BAeOwe+DR2Ha5t9j+R9fQ+40IHX5LycotfUh/fKGBhQPj8Btk9Q+pPPyYE2/FuVLy1H6TimKXyuGW7gbgqcFI/iGYBiHG3mR+AVo70PqqfQhfc7vbqUPqUcYru+iD2mbpQ1lDWWnB6n2v+tLsLd8L0rrS2GRlk7r+7r79ihw9XH34TlIdC6yDWByV/qQInLBqYFOHNA0YAYsIBVCLAFwBYAgIcQxAH8BlC5bUsrXAHwG4H8AHATQCODWgSpLX3UcTf/aVmXkXcfR9wMdlNZtrWsPRpdnL8Br5Wo5rpuL5UB7UFq3dfAvIiC1H01frI6yP230/aMfI23pnTDXm3FizQmULy3H8VeO49jCYzDEGBA8IxjBM4LhleHFwOACZD+a/rXqBACdR987Gtik1+oR4ROBCB/nt+is0orKxkqngeuPR39ESX0Jms3Nndb31Hsi1Du028A10DMQGsEpo4nOCvvR9FK9BnQcfc+gdEAMWEAqpbyhm+USwB8Gavv9aeeqz/DEdc+3T+302tYf25edFpSuehBjxw7cpPSHElZi2uaHsDx7AcZeNxevvW5XDvugNGMBInFhv2E6Te1kVxcdp4Tyn3cnQmaEIGRGCNqq21D5cSXKl5ajaH4Rip4pgmeKZ3tw6pno6cK9ov7ScWqn094rPQhKe0IjNAj2CkawVzAykdllOiklalpqnAaue8r24MtDX6K2pbbT+nqNHiHeIQg3hncZtIYZwxDsFQydxpU3vYjOcx2ndrK7bjAoHXi8evXA1jEf4C/RjucZBU4FpVuPfICxGLiAdGvu1+3BqMNyqEHp1tyvu0xzoajbVIzUR9Hl1E62oLRuUzHs24r1fnqE3RqGsFvD0FreioqPKlC+tBxH/nIER/5yBN5Z3gi+IRjB04JhiDKcnZ2hfrf16LdOp3ayBaVbj36LsQNcFiEE/Ax+8DP4IcWU4jRtQ2sDSutL2wPW4rri0/q5Hqo6hA1FG3Ci6UTn7UAg2CvYaWtrmDEMod6hMOh4bhN1UvA1EOtkaidbUFrwNXCBN/q4woBO+zQQXDkPqc109VvTsrsu6SblL6Mc54K+1kXzsWZULFeC07qtdQAAn0t9EDwjGKapJriHunZ2B+qbC+290mppVQJXJ62uJXUlKGsog1V2njXD3+Dfo36uRnejC/aO6NzQX9cNzkPaM2whJQJgiDBg8NzBGDx3MJoONaF8WTnKl5bj4JyDOHj/Qfhd4acEp1NM0Af8ImevpHOIm9YNkb6RiPSNdJrOYrWgorHCaeC6vnA9SupL0Gpp7bS+l96rR4FrgEcA+2ETUZ8wICXqwCPOA1F/jkLUn6PQsK9BCU6XlOPAnQeQf08+/H/rj+AZwQi6Jgg6I99CdO7SarQI9Q5FqHcospDVZTopJaqaq5wGrjtKduCz+s9Q39p5rmM3rVuPBmgFewVDq9EO5C4T0XmKn6ZETnileSHmrzGIfiIa9T/Vo3xpOcqXlSPv0zxoDBoETAhA8IxgBE4IhNaDH7R0fhJCIMAjAAEeAUgLTnOatr613mngmn8iH+sK1+Fk08lO69oGgnUXuIZ6h8Jdx24yRL8kDEiJekAIAeNQI4xDjYh9Lha1P9YqwenyclR+VAmttxaB1wQi5IYQ+P/aHxo3TtNDFyZvN28kBCYgITDBaboWc8tpA7Qc9XH9qeQnlDeUO+znGuAR0G3gGmYMg7eb90DtKhGdRQxIic6Q0Aj4XuYL38t8EfdiHGq+r0H50nJlxP4H5dD562Caojwdyu8KPwgt+9bRL4+7zh1RflGI8otyms5sNaOiocJp4HrgxAGU1JWgzdrWaX1vN+8eBa7+Bn/2cyU6hzEgJeoDjU4D/yv94X+lPxL+mYCTX55E+dJylC0pQ8mbJdCH6BE8VZnj1OcSHz66lKgDnUanBI7GMCCs63RSSpxsOuk0cN1esh0ldSVoaGvotL671l3p59pN4GryNLGfK5ELMCAl6icaNw2CJgYhaGIQLI0WnPhMeTpU8RvFOP7ycbhHuiN4uhKcemd5s7WG6AwIIRDoGYhAz0CkB6c7TVvXUoeSenUeVwfBa15lHnKO5KC6ubrTulqhPW0+1/YHEnQIXkO8Q+CmdRuo3SX6xWFASjQAtJ5aBF8fjODrg2GuNaPyk0qULynHsReP4ejfj8IjwePUo0tTvVxdXKILitHdCKO7EYmBiU7TNbU1Oe3neqz2GLYWb0VFQwUkOs/ZHeQZ1KPuAp56PgGOqDsMSIkGmM5Hh9AbQxF6YyjaTrSh4j/KBPyFTxWi8MlCeGV4KcHp9GB4xHm4urhEvxgeeg/E+Mcgxj/GaTqz1Yyy+jKn3QVyK3JRWl8Ks9XcaX0fd58eBa6+7r68c0K/WAxIic4ifaAe4XeEI/yOcLSUtKBipRKcHn7kMA4/chjGEUYlOJ0WDPdBnPaG6Fyg0+gwyGcQBvkMcprOKq040XjCaeC6+fhmlNSVoMnc1Gl9g87Qo8A1yDMIGsGZPOjCwoCUyEXcw9wR8ccIRPwxAs2Fze1Phzo09xAOPXgIvqN9ladDXW+Cm4l91YjOdRqhgcnLBJOXCUNChnSZTkqJ2pZap4Hrvop9+Lrga9S01HRaX6fRIcQrpNvANcQrBHotnyxH5wcGpETnAEOUAZEPRyLy4Ug07m9sfzpU/j35yP9jPvyv9EfwDcEIujYIej9+wBCdz4QQ8DX4wtfgi+SgZKdpG9salX6uXQSuhTWF2HRsEyoaKzpvB0Lp59qDx7966NldiFyLASnROcYzyRPR/y8aUY9FoWFPgzIB/9Jy7L91Pw7cdQAB45WnQwVNCoLWi9PTEF3IPPWeiPWPRax/rNN0bZY2lDWUOX2K1t7yvSitL4VFWjqt7+vu26PA1cfdh/1caUAwICU6Rwkh4D3EG95DvBHzdAzqttS1P7r0xH9PQOOpQeCkQATPCEbAVQHQGhicEv1S6bV6RPhEIMInwmk6q7SisrGyPVA9bWosNYDdeHQjSupK0GJp6bS+h86jR4FroGcg+7nSGWFASnQeEELAJ9sHPtk+iFsQh5oNytOhyleUo2JZBbQ+Wpgmq0+HGucHjZ4fBETUmUZoEOwVjGCvYGQis8t0UkpUN1c77ee6u2w31h5ci7rWuk7r6zV6hHiHdBu4hniHQKdhKEIMSInOO0Ir4DfGD35j/BC/KB7V31ajbEkZKv5TgdK3S6EP0sN0vRKc+o725dOhiOiMCSHg7+EPfw9/pJpSnaZtaG1wGrgWVBXgh6IfcKLpROftQMDkZerR7AIGnWGgdhcAMP+H+RgePhxjY8Z2mSbncA62Fm/Fw5c9PKBl+SViQEp0HtPoNQj4bQACfhsAy2sWnPxCeXRp6TulKH6tGG7hbgiepkzAbxxhZN8vIup3Xm5eiA+IR3xAvNN0rZZWxwO07ALYXaW7UNZQBqu0dlrfz+B36ulZToJXo7uxV/sxPHw4pq2chuXXL3cYlOYczmlfTv2PASnRBUJr0MJ0rQmma00w15txYo3y6NLjrxzHsYXHYIgxnHo6VIYXg1MiOqvctG6I9I1EpG+k03QWqwUVjRVOA9f1hetRUl+CVktrp/W99F496uca4BFw2nVwbMxYLL9+uV3QeapF1j4YddaCSr3HgJToAqTz1iFkRghCZoSgrboNlR9XonxpOYrmF6HomSJ4pni2B6eeiXysIRGdO7QaLUK9QxHqHYosZHWZTkqJquYqp4HrjpId+Kz+M9S31nda303rhlDv0E6B682ZN+PaZdciU/9vBHoE4puCbzDjoxkMRgcYA1KiC5zeT4+wW8MQdmsYWstbUfGR8nSoI48fwZG/HIF3lnf7o0sNUQPbR4uIqL8IIRDgEYAAjwCkBac5TVvfWu80cM0/kY91hetwsulk+zoHag8AANavXIAVU1cwGB1gDEiJfkHcgt0w6O5BGHT3IDQfa0bFigqULylHwbwCFMwrgM+lPsrToaaa4B7KR5cS0YXB280bCYEJSAhMcJquxdyi9HOtL8Edb+9DRWMF7h52N4PRs4BzwxD9QhkiDBj8wGAM3TIU2QezEfN0DCx1FhyccxA/DvoRlrPHiwAAIABJREFUO6/cieI3itF2os3VRSUiOivcde6I8otCU1sTqpurEeUbhde2v4acwzmuLtoFjwEpEcEjzgNRf47C8N3DMXzvcEQ9EoWWohYcuPMANoZuxO6Ju1H6finMdWZXF5WIaEDZBjClmlIR7RfdPtCJQenAYkBKRKfxSvNCzF9jMOLACAzdPhQRD0SgYXcD8m7Kw8bgjdh7/V6UryyHpanz4weJiM5n9qPp/Qx+AE4ffc+gdOAwICUih4QQMF5sRNz8OIw8MhJZG7IQdnsYatbXIHdqLjYGb0TujbmoXFMJa2vnOQOJiM4nzqZ2YlA68DioiYi6JTQCvpf5wvcyX8S9GIea75VHl1Z8VIHyD8qh89fBNEV9dOkVfhBaznFKROeXrcVbnU7tZAtKtxZv5SCnAcCAlIjOiEangf+V/vC/0h8J/0xA1VdVKFtShvKl5Sh5swT6ED2CpypznPpc4sNHlxLReaEnjwMdGzOWwegAYUBKRL2mcdMgcEIgAicEwtJowYnPlKdDFb9RjOMvH4f7YHcETw9G8A3B8M7y5tOhiIjIIQakRNQvtJ5aBF8fjODrg2GuNaPyE+XpUMcWHsPRBUfhkeBx6tGlqV6uLi4REZ1DGJASUb/T+egQemMoQm8MRduJNlT8R3k6VOFThSh8shBeGV7tT4fyiPNwdXGJiMjFOMqeiAaUPlCP8DvCcdE3F+GS45cgflE8tEYtDj9yGJvjN2N79nYcffEoWo63uLqoRETkIgxIieiscQ9zR8QfI3DxDxdj5JGRiJ0fC9kmcWjuIfw4+EfsGLMDx189jtaKVlcXlYiIziIGpETkEoYoAyL/NxLDfhqGEXkjEP14NNrK25B/Tz42hm3Ert/uQsm/S9BWzUeXEhFd6BiQEpHLeSZ5Ivr/RWN47nAM2zUMkQ9Hoim/Cftv24+NIRux59o9KFtaBksDnw5FRHQh4qAmIjpnCCHgPcQb3kO8EfN0DOq21qF8STnKl5XjxH9PQOOpQeCkQATPCEbAVQHQGrSuLjIREfUDBqREdE4SQsBnhA98RvggbkEcajYoT4cqX1GOimUV0PpoEXRdEEJuCIHfOD9o9LzhQ0R0vmJASkTnPKEV8BvjB78xfohfFI/qb6uVR5f+pwJl75RBH6SH6Xrl0aW+o335dCgiovMMA1IiOq9o9BoE/DYAAb8NQMKrCTj5xUmULy1H6TulKH6tGG7hbgiepkzAbxxh5NOhiIjOAwxIiei8pTVoYbrWBNO1JpjrzTixRnl06fFXjuPYwmMwxBiU/qZaK04OYmBKRHSuYkBKRBcEnbcOITNCEDIjBG3VbahcpTy6tGh+EaZbgJOhAkfKjyB4RjA8Ez1dXVwiIrLDUQBEdMHR++kRdksYMr/IxKUll2LdDTo0G4Ejjx/BlqQt2HbxNhTNL0JzYbOri0pERGBASkQXODeTG/aN0eK/D7phZNFIxL0QB6EXKJhXgE3Rm/DTZT/h2EvH0FLKR5cSEbkKA1Ii+sUwRBgw+IHBGLp5KLIPZSPmbzGw1FtwcM5B/DjoR+y8cieK3yhG2wk+HYqI6GxiQEpEv0gesR6I+r8oDN81HMP3DUfUI1FoKWrBgTsPYGPoRuyeuBul75fCXGt2dVGJiC54HNRERL94XqleiPlrDKKfiEb9jnplAv6l5cj7NA8agwYBEwIQPCMYgRMCofXg06GIiPobA1IiIpUQAsaLjTBebETss7Go3VSrBKfLy1H5USW03loEXqM+uvQ3AdC48SYTEVF/YEBKROSA0Aj4XuoL30t9EfdCHGq+Vx5dWvFRBco/KIfOXwfTFOXpUH5X+EFoOc8pEVFvMSAlIuqGRqeB/5X+8L/SHwn/TEDVV1Xtt/VL3iyBPkSP4KnK06F8LvHho0uJiM7Q/2/vzuPrquv8j78+ublZmqXZu6fpkrYECnRJaIsbi6xqVQRaYUZEhh8qOAgqICKLg0th0EEERUWQUcoqVkVhdAqOpJRudAtN96ZJl6Rt2qaltEn6+f1xb2soSXoLvTk3yfv5eOTRc84999xP0hLffs/5fj8KpCIixyApJYn8C/PJvzCf1n2tbP/T9sPBtO6BOlKHpFJ0aRFF04vIHJep1qUiIjFQIBUReY9C6SGKPlNE0WeKaNndwrZZke5QtT+qZeO9G0kvTadoWmTkNKMsI+hyRUQSlgKpiMhxkJydTP/L+9P/8v40b2+m4XcN1M+sZ8PdG9jwnQ1kjM2IhNNLi0gfkR50uSIiCUVTREVEjrNwfpiBVw3k1L+eyuS6yYy8fyShrBDrbl3H3JFzWXDaAjb+cCP769QdSkQEFEhFROIqtX8qg68bzPhXxzNp/SSGzxiOtzhrbljDnCFzWPThRdQ9VMeBhgNBlyoiEpi4BlIzO8/Mqs1stZnd3M7rxWY228wWmdkSM7sgnvWIiAQpbWgaxV8vZuKCiVRUV1ByZwnNDc2s+tIqKgdUsvjcxWz+1Waad6p1qYj0LnELpGYWAn4CnA+UAdPNrOyI074FPOXu44BpwIPxqkdEJJH0GdWHkttKKF9ezsTFEyn+RjH7Vu2j+spqKvtVsvSTS9k6cyute1uDLlVEJO7iOampAljt7msBzGwmMBWoanOOA9nR7b7ApjjWIyKScMyMzJMzyTw5k2F3D6NpXlNkjdMn69n+++0k9Uki/+PR7lDn5RFKU+tSEel54hlIBwEb2+zXAqcdcc4dwEtmdh2QAZzd3oXM7GrgaoDi4uLjXqiISCIwM7IrssmuyGbEvSPY9X/R7lDPNNDwZAOh7BAFnyqg3/R+5JyZQ1JY0wBEpGeI52+z9laD9iP2pwOPuvtg4ALgcTN7V03u/rC7T3T3iYWFhXEoVUQksViSkfPhHEY9NIrJmyZz8l9OpvDThWz73TaWnLeEOQPnsPKLK9n5yk689chfrSIi3Us8R0hrgSFt9gfz7lvyXwDOA3D3OWaWBhQA9XGsS0SkW0kKJ5F3bh555+ZR+lApjS9GWpdu+fUWNv10EykDUyi6JLIAf1ZFlrpDiUi3E89AOg8oNbNhQB2RSUufPeKcGuAs4FEzOwFIAxriWJOISLcWSgtRMLWAgqkFtO5tZdsfIt2h6h6so/ZHtaQNS/tnd6ixGQqnItItxC2QunuLmV0LvAiEgEfcfbmZ3QXMd/dZwI3Az83sq0Ru51/h7rr3JCISg1BGiH7T+tFvWj+adzaz7flIOK2ZUUPN92roc0Kfw+G0z6g+QZcrItKhuLYOdfcXgBeOOPbtNttVwOnxrEFEpDcI54QZcMUABlwxgAMNB2h4toH6J+pZf8d61t++nsxxmYdbl6YNTQu6XBGRd9AUTRGRHialMIVB1wxi3CvjmFQziRH3jcDCxtqb1vJayWssPH0htT+uZf8WtS4VkcSgQCoi0oOlDU5jyFeHMGHuBE5bcxrDvjuM1j2trP7KauYMmsMbZ73Bpp9vonm7ukOJSHAUSEVEeon04ekMvWUo5YvLKV9eztBbh7J/435WXr2Syv6VLPnYErb89xZadrcEXaqI9DIdPkNqZk28e93Qw9w9u6PXREQksWWUZTDsrmGU3FnCnkV7It2hZtaz4k8rSEpLIu/CPIqmFZF/YT6hdHWHEpH46jCQunsWQHRW/BbgcSKL3V8GZHVJdSIiEldmRtb4LLLGZzH8+8PZ/druSDh9qp5tz24jlBkif2q0dek5eSSl6MaaiBx/scyyP9fd27b8fMjM5gIz4lSTiIgEwJKMvlP60ndKX0bcN4Jdr0Rblz7bQP1v6knOTabwokKKphWR85EcLKQ1TkXk+IglkLaa2WXATCK38KcDrXGtSkREApWUnETuWbnknpVL6U9KafyfxsO39Tf/YjPhfmGKLo6scZo9ORtLUjgVkfculkD6WeC/ol8OvMq7Oy6JiEgPlZSSRP6F+eRfmE/rvlZ2vLCDrU9sZfMvNlP3QB2pQ1IpujQSTjPHZ6o7lIgcs6MGUndfD0yNfykiIpLoQukhCi8qpPCiQlp2t7BtVqQ7VO2Patl470bSS9P/2bq0LCPockWkmzhqIDWzNOALwIlEes0D4O5XxrEuERFJcMnZyfS/vD/9L+9P845mGp5roH5mPRvu3sCG72wgY2zG4e5Q6SPSgy5XRBJYLNMlHwf6A+cCrwCDgaZ4FiUiIt1LOC/MwKsGcupfT2Vy3WRG/ngkoawQ625dx9yRc1lQsYCN921kf526Q4nIu8USSEe6+23AXnd/DLgQGBvfskREpLtK7Z/K4GsHM/7V8UxaP4nhM4bjrc6aG9cwZ8gcFn14EXUP1XGg4UDQpYpIgoglkB7qJ7fTzE4C+gIlcatIRER6jLShaRR/vZiJCyZSUV1ByZ0lNDc0s+pLq6gcUMnicxez+Vebad6p1qUivVksgfRhM8sFbgNmAVVoDVIRETlGfUb1oeS2EsqXlzNxyUSKv1HMvlX7qL6ymsp+lSz95FK2ztxK616tLCjS28Qyy/4X0c1XgOHxLUdERHo6MyNzbCaZYzMZdvcwmuY1RdY4fbKe7b/fTlKfJPI/Hu0OdV4eoTS1LhXp6TrrZX9DZ2909/uOfzkiItKbmBnZFdlkV2Qz4t4R7PpHtDvU0w00PNlAKDtEwacKKJpWRO5ZuSSF1bpUpCfqbIT0UL/60UA5kdv1AB8H/h7PokREpPexJCPnQznkfCiHkfePZOffdkbC6XMNbH1sK+GCMIWfibQu7fuBvmpdKtKDdBhI3f1OADN7CRjv7k3R/TuAp7ukOhER6ZWSkpPIOzePvHPzKH2olMYXI61Lt/x6C5t+uomUgSkUXRJZgD+rIkvdoUS6uVhahxYDbdfmOIBm2YuISBcJpYUomFpAwdQCWve2sv2P26mfWU/dg3XU/qiWtJK0yAL804vIGJuhcCrSDcUSSB8HXjez3xHpZf8p4NdxrUpERKQdoYwQRZdGuj8172xm2/OR1qU199RQ8/0a+pzQ53Dr0j6j+gRdrojEKJZZ9neb2Z+BD0YPfd7dF8W3LBERkc6Fc8IMuGIAA64YwIGGAzQ8G2lduv6O9ay/fT2Z4zIPty5NG5p29AuKSGA6m2Wf7e67zSwPWB/9OvRanrvviH95IiIiR5dSmMKgawYx6JpB7K/bT/3T9dTPrGftTWtZe9NasqdkUzStiMKLC0ntnxp0uSJyhM5GSH8LfAxYQORW/SEW3deapCIiknBSB6Uy5PohDLl+CPvW7qP+yUg4Xf2V1ay+fjU5H8mJhNNPFxLODwddrojQ+Sz7j0X/HNZ15YiIiBw/6cPTGXrLUIbeMpS9VXsj4fSJelZevZJVX1pF7jm5FE0romBqAcnZsUyrEJF4OOoKw2b2KTPr22Y/x8w+Gd+yREREjq+MsgyG3TmMiuoKJiycwOCvDmbvsr2s+NcVVParZNlnllH/TD2t+9S6VKSrxdLy4nZ333Vox913ArfHr6TEU1Mzg8bG2Z2e09g4m5qaGV1UkYiIvFdmRta4LEbMGMGkdZMY9+o4BvzbAHb9YxdVF1dRWVRJ1eVVbPvjNg4eOBh0uSK9QiyBtL1zetV9jayscqqqLukwlDY2zqaq6hKyssq7uDIREXk/LMnoO6UvpfeXMqVuCqf87RSKphex44UdLPv4Mir7V7LiqhU0/q0Rb/WjX1BE3pNYguV8M7sP+AmRyUzXEZno1Gvk5p5BWdlTVFVdQlnZU8A/lw85FEbLyp4iN/eM4IoUEZH3xUJG7pm55J6ZS+kDpTT+T6Q7VMOTDWz55RbC/cIUXRxZ4zR7cjaWpAX4RY6XWEZIryPSnelJIi1D3wa+HM+iElHbUDowPZLHFUZFRHqmpJQk8i/M54THT2BK/RROfOZEcj6Yw+ZfbGbRBxbxWslrrPn6GpoWNOGukVOR9yuWhfH3AjebWTZw0N33xL+sxHQolJ7/9sfYtG8cVVXVCqMiIj1cKD1E4UWFFF5USEtTC9tnbWfrE1up/VEtG+/dSHpp+uHuUBllGUGXK9ItHTWQmtlYIq1C86L724DPufuyONeWkHJyPsJbrbmUZL5KYeGXFUZFRHqR5Kxk+l3Wj36X9aN5RzMNz0W6Q224ewMbvrOBjLEZh7tDpY9ID7pckW4jllv2PwNucPeh7j4UuBF4OL5lJa6dO18mLdREy8EUNm/+GTt2/DXokkREJADhvDADrxrIqX89lcl1kxn545GEskOsu3Udc0fOZUHFAjbet5H9dfuDLlUk4cUSSDPc/fD0cnd/GeiV9yQOPTP6Yt3dvLL1JtxbWLbsk0ddEkpERHq21P6pDL52MOP/MZ5JGyYxfMZwvNVZc+Ma5gyZw6IPL6LuoToONBwIulSRhBRLIF1rZreZWUn061vAungXlmjaTmDatG8CK3efR37+J3A/wPLlFymUiogIAGnFaRR/vZiJCyZSUV1ByZ0lNDc0s+pLq6gcUMnicxez+Vebad7ZHHSpIgkjlkB6JVAIPAf8Lrr9+XgWlWjan01vjBr1M0KhLMLhfp2uUyoiIr1Tn1F9KLmthPLl5UxcMpHim4rZt3of1VdWU9mvkqVTl7J15lZa96o7lPRuscyybwS+0gW1JKympnntzqZPTe1PaekDvPnmZxkw4GqamuZpkpOIiLyLmZE5NpPMsZkM+49hNM1ron5mPfVP1rN91naS+iSR//F8iqYVkXdeHqG0UNAli3SpDgOpmf2ByEL47XL3T8SlogRUXPyNDl8rKppGQ8OzbNnyKBMnLuzCqkREpDsyM7IrssmuyGbEvSPY9Y9dkQX4n26g4ckGQtkhCj5VQNG0InLPyiUpHMvNTJHurbMR0nu7rIpuzMwYNepB5s17hTff/Bzjx88hKSkcdFkiItINWJKR86Eccj6Uw8j7R7Lzf3dS/0Q9Dc81sPWxrSTnJ1P4mUL6Te9H3w/0xULqDiU9U4eB1N1fObRtZulAsbtXd0lV3UxKShGlpQ9SVXUJGzfOYOjQW4MuSUREupmk5CTyzskj75w8Rv10FDv+soP6mfVsfXwrm3+2mZSBKRRdElmAP6siCzOFU+k5jnofwMw+DrwB/CW6f6qZzYp3Yd1NUdHFFBZeyvr1d7Jnz5KgyxERkW4sKTWJgqkFlD1Rxun1p1M2s4zsimzqHqxj4aSFzB0+l7W3rGXP4j1qXSo9QiwPptwBVAA7Adz9DaAkfiV1X6WlD5CcnMuKFZ/j4EEt5yEiIu9fKCNE0aVFnPS7k5iydQqjfzWa9NHp1NxTw/xT5zOvbB7r71rPWyvfCrpUkfcslkDa4u674l5JD5CSUsCoUT9lz543qKn5btDliIhIDxPOCTPgigGc8pdTmLJ5CqUPlRLuF2b9Het5ffTrzB8/n5oZNby94e2gSxU5JrEE0mVm9lkgZGalZvZjoDLOdXVbhYWfoqjoMjZs+A+amhYFXY6IiPRQKYUpDLpmEONeHsfkjZMZ8cMRWIqx9qa1vFbyGgunLKT2x7Xs36LWpZL4Ygmk1wEnAvuB3wK7gOvjWVR3V1p6P+FwYfTWvdrEiYhIfKUOSmXI9UOY8NoETltzGsO+O4zWva2s/spq5gyawxtnvcGmn2+iebseJ5PEFEsgHe3ut7p7efTrW+6uewGdCIfzGDXqYfbuXcr69XcFXY6IiPQi6cPTGXrLUMoXl1O+vJyh3xrK/o37WXn1Sir7V7LkwiVseXwLLbtbgi5V5LBYAul9ZrbCzL5jZifGvaIeoqDgY/TvfwU1Nd9n9+55QZcjIiK9UEZZBsPuHEZFdQUTFk5g8A2D2btsLyv+dQWvFr3KsouWUf9MPa371LpUgnXUQOruZwAfARqAh81sqZl9K96F9QQjRvyQlJT+rFhxBa2tGlQWEZFgmBlZ47IY8YMRTFo3iXGvjmPg1QPZ9eouqi6uorKokqrLq9j2x20cPHAw6HKlF4qpH5m7b3H3+4FriKxJ+u24VtVDhMM5jB79C956q4r16+8IuhwREREsyeg7pS+l95cypW4Kp/ztFIqmF7HjhR0s+/gyKvtXsuKqFez46w4OtiicSteIZWH8E8zsDjNbBjxAZIb94LhX1kPk55/HgAFXsXHjPeza9VrQ5YiIiBxmISP3zFxGPzyaKVumMPZPY8m/MJ+GJxtY8tElzBk0h1XXrWLXq7vwg1qAX+Kns172h/wKeAI4x903xbmeHmnEiP9kx46XWLHiCiZOXEQolB50SSIiIu+QlJJE/gX55F+QT+u+Vna8EGlduvkXm6l7oI7UIakUXRppXZo5PlOtS+W4OmogdfdJXVFIT5acnM3o0b9kyZKPsm7dbYwceW/QJYmIiHQolB6i8KJCCi8qpKWphe2ztlM/s57a/6pl470bSS9Np2haJJxmlGUEXa70ADE9QyrvX17e2Qwc+EVqa+9j165Xgy5HREQkJslZyfS7rB9j/zCWKVumMOrno0gtTmXD3RuYd+I85p08jw3f3cC+NfuCLlW6MQXSLjR8+AzS0oZGZ93vDbocERGRYxLOCzPwqoGc+tdTmVw3mZE/HkkoO8S6W9cxd+RcFlQsYON9G3m7VivLyLGJOZCaWZaZZcazmJ4uOTmT0aN/xb59q1m79ptBlyMiIvKepfZPZfC1gxn/j/FM2jCJ4fcMxw86a25cw2tDXmPRhxZR91AdBxrUsVCOLpZZ9mPNbBGwDKgyswVmdlIsFzez88ys2sxWm9nNHZxziZlVmdlyM/vtsZXf/eTmfoRBg66jru5+du58JehyRERE3re04jSKv1bMxPkTqVhZQcldJTRva2bVl1ZROaCSxecuZvOvNtO8U61LpX2xjJD+DLjB3Ye6ezFwI/Dw0d5kZiHgJ8D5QBkw3czKjjinFLgFON3dTwSuP8b6u6Xhw79HWtoIVqz4PC0te4IuR0RE5LjpU9qHkttKKF9ezsQlEym+qZh9q/dRfWU1lf0qWTp1KVuf2ErLHrUulX+KJZBmuPvsQzvu/jIQy5S6CmC1u6919wPATGDqEef8G/ATd2+MXrs+pqq7uVAogzFjHuXtt9ezdu1NQZcjIiJy3JkZmWMzGX73cE5bfRrjXx/PoGsH0bSgiTc/+yaV/SpZPm05Dc830Pq2Wpf2drGsQ7rWzG4DHo/uXw6si+F9g4CNbfZrgdOOOGcUgJm9CoSAO9z9LzFcu9vLyfkAgwd/ldra+ygs/DS5uWcFXZKIiEhcmBnZ5dlkl2cz4p4R7PrHLupn1tPwdAMNTzYQyg5R8KkCiqYVkXtWLklhzbnubWL5G78SKASei34VAFfE8L72Vsw9ss1DMlAKfASYDvzCzHLedSGzq81svpnNb2hoiOGju4dhw/6D9PRRrFhxJS0tu4MuR0REJO4sycj5UA6jHhzF5M2TOfnFkym8qJBtz29j6flLqRxQSfU11TS+3Ii3qjtUbxFLID3b3b/i7uOjX9cDH43hfbXAkDb7g4EjOz3VAr9392Z3XwdUEwmo7+DuD7v7RHefWFhYGMNHdw+hUDpjxjzG/v21rFnz9aDLERER6VJJyUnknZPHmEfGcPrW0znp+ZPI+2geWx/fyuIzFjOneA6rv7qa3XN3465w2pPFEkhvifHYkeYBpWY2zMxSgGnArCPOeR44A8DMCojcwl8bw7V7jL59JzFkyNfYvPlhdux4MehyREREApGUmkTB1ALKnijj9PrTKZtZRnZFNnUP1rFw0kLmDp/L2lvWsmfxHoXTHqjDZ0jN7HzgAmCQmd3f5qVs4KhT49y9xcyuBV4k8nzoI+6+3MzuAua7+6zoa+eYWRXQCnzd3be/92+neyopuZPt2//AihVfoLx8GeHwu55aEBER6TVCGSGKLi2i6NIiWna1sO35bdTPrKfmnhpqvl9DnzF9KJoeaV3aZ1SfoMuV46CzSU2bgPnAJ4AFbY43AV+N5eLu/gLwwhHHvt1m24Ebol+9ViiUxpgxj7Fw4WTWrLmBMWMeCbokERGRhJDcN5n+n+tP/8/150DDARqebaB+Zj3r71jP+tvXkzkuk6JpkfCaNjQt6HLlPeowkLr7YmCxmf3W3bWSbZxlZ5dTXHwTNTXfpbDwIvLzLwy6JBERkYSSUpjCoGsGMeiaQeyv20/90/XUz6xn7U1rWXvTWrInZ1M0rYjCiwtJHZAadLlyDGJ5hrTCzP7HzFaa2VozW2dmveo5z65SUvJtMjLGUl39bzQ3NwZdjoiISMJKHZTKkOuHMOG1CZy25jSGfW8YrW+1svrfVzNn8BzeOOsNNv18E83bNabWHcQSSH8J3Ad8ACgHJkb/lOMsKSmVMWMepbm5gdWr/z3ockRERLqF9OHpDL15KOVvlFO+vJyh3xrK/o37WXn1Sir7V7LkwiVseXwLLbvVHSpRxRJId7n7n9293t23H/qKe2W9VFbWeIqLb2Xr1sfZtu33QZcjIiLSrWSUZTDszmFUVFcwYeEEBt8wmL3L9rLiX1fwatGrLLtoGfXP1NP61ju7Q9XMqKFxdud3JxtnN1Izoyae5fdasQTS2WZ2j5lNNrPxh77iXlkvNnToN8nMPJXq6v9Hc7Oyv4iIyLEyM7LGZTHiByOYtG4S4yrHMfD/DWR35W6qLq6isl8lVZdXse2P2zh44CBZ5VlUXVLVYShtnN1I1SVVZJVndfF30jvE0jr0ULvPiW2OOXDm8S9HAJKSUhgz5lEWLChn1aprKSt7IuiSREREui1LMvpO7kvfyX0Zed9Idr6yM9K69JkG6n9TT3JuMgWfLmDITUOouqSKsqfK3vH+Q2G07Kkycs/IDei76NmOGkjd/YyuKETeKTPzFIYO/Tbr199GQcFFFBV9JuiSREREuj0LGbln5pJ7Zi6lD5TS+NfGSDh9soHWPa2EckIsvWAp+79+kNRBqQqjXeSot+zNrJ+Z/dLM/hzdLzOzL8S/NCkuvonMzAmsWvVFDhyoD7qchFJTM4PGxtmdntPYOJuamhldVJHw+qSeAAAXbklEQVSIiHQ3SSlJ5F+Qzwm/PoEp9VM48dkTyTs7D2919q3ex65/7GL5Z5YrjHaBWJ4hfZRIR6WB0f2VwPXxKkj+KSkpzAknPEZLy25WrvySWqW1kZVVTlXVJR2G0sbG2VRVXUJWlhaEEBGRowulhyj8dCEnPn0ip28/nXBBGG91Bn5poMJoF4glkBa4+1PAQYi0BCXS5lO6QEbGiQwbdhfbtj1LQ8NTQZeTMHJzz6Cs7Kl2Q+mhMFpW9hS5uXriREREjk3T/CZad7WQNjSNzT/dfNTZ9/L+xRJI95pZPpGJTJjZJGBXXKuSdxg8+Eaysk5j5covsX//lqDLSRhtQ+mQPpVkJG9l27Y/KIyKiMh7duiZ0T5lGaSVpFH2VFmns+/l+Ihllv0NwCxghJm9ChQCmmHThZKSkhkz5lHmzz+VlSuv4aSTfoeZBV1WXLm30ty8jQMH6mlurufAga3v2I78GdluadnNx4Z8DYBlywCSqKqaRjicR3JyPuFwfkzboVB6oN+ziIgEq+0EpuSVKwDIPSP3cCjVs6TxE8ss+4Vm9mFgNGBAtXrbd72MjDEMH343a9Z8jfr639Kv32VBl3TMWlvfeleYPLTd3Lz1Hceam7cRHZR/B7NkwuEiUlKKCIf70afPaMLhIl6rfoXBGfPJzT2brKxympt30NKynebm7bz99gb27FlIc/N2Dh7c12F9SUlpHYTWfJKT8zrYziUpKRzHn5qIiHSFd82mX/nP1xRK4++ogdTMQsAFQEn0/HPMDHe/L861yREOHmymT58TWbXqWnJy2r8d3dg4m6ameRQXfyPu9bgfpLl5x7vCZNuA2XZ08+DBve1eJxTKjgbMIvr0GUU4/AFSUopISen3jvCZklJEcnLuu0aHGxtnk5/6S+Zv+zyTw3+guPibHd6ub23dR0vLDpqbt78jtLa3/dZbVYe3I49Oty8Uyj5KaH33dnJyX8xieWJGRES6QtO8pk7D5qFQ2jSvSYE0DmK5Zf8H4G1gKdGJTRKM7OzT2LhxBq2tb1FdfTXwTSKD1hFtJ/O8V62tb7cbJtu7Vd7c3ED7/yRCpKQURsNkP7KzR3QYMMPhwvd1q/zQ9/zSpu+wad8EvnDWv3T6DGkolE4oNIjU1EExf4a709raRHPz9jZhtuPtt99eGz22k/ZGeSOSSE7OjTnAHtoOhTJ6/OMaIiJBKP5G8VHPyT0jV2E0TmIJpIPd/eS4VyJHlZt7Biee+CxLl36cHTv+xOjsU6nefSHQ8cxy94O0tOyM+VZ5a2tTu58dCmUeDpNpacPIzj7tcOA8NLp5KHCGw3ldMvrX9nvetCzt8M/o0ESn4zWxycxITs4mOTkbGBbz+9xbaWnZedQA29KygwMHNrF371JaWnbQ2rqnk1pSjnk0NhzOJykp5X3/HEREROIllkD6ZzM7x91fins1clS5uWdw0km/Z+nS8/lA0X9y4GAGa9b8nrq6B8jLu4AtWx6hpub7bUY0Gzq43ZxEOFxweLQyO7uiw4CZklJEKNSny7/Xzrw7gM85/Fo8Qul7YRY6HAiPxcGD+6OPChx9NHbfvlWHt90PdHjNUCjzmENscnIOkSd2up+amhlkZZV3+nfflY+3iIhI52IJpK8Bv7PIkFczkXvE7u7Zca1MOpSXdxajR/+KN9+8nPMGfZONGyPHd+z44+EQmZo6hMzMCR0GzHA4v9uGDYCmpnmdhs1DobSpaV63W/4pKSmV1NQBpKYOiPk9kccK9sYUYltadvD22zXR7UY6fhLHSE7OOeYR2VAoK/DHCg41Tujo38jxeLxFRESOn1gC6X8Ck4GlrlZBCaN//8t4snIWp+Q9xaBB1zJs2PdITs4MuqwuE8uoVm7uGd0ujL5XkccKMklOziQt7ejPQR0SeaRjV0zPxx44UM9bb62guXk7ra27O6kl+T2MxuYTCqUdjx8F8O5RcvjntdU4QUQk8cQSSFcByxRGE0tj42xGZb/E/G2fJxyeSUHBp/U/rnLMzJIIh3MJh4/tIf2DB5tpaWmMcTR2PU1NC2hp2XGUZbfSD4fTcDgvpu3k5DySktr/NdY2lA5Mv51N+yYojIqIJKhYAulm4GUz+zOw/9BBLfsUnGOdWS5yvCUlhaMrJxQd0/taW/cdJcBujy4ltp29e5cd3u6sW3Eo1LfT0DpgwNWc9/bNVO86n6qql/XfiYhIAoolkK6LfqVEvyRAXTWzXCQeIstuDQYGx/yeyPOxuw+H07ahtb3tfftW09JyaNmtiNQQnJz3DAMH3qb/PkREElAsnZruBDCzDHdvf2Vz6RLdYWa5yPEWeT62L8nJfUlPP7Zlt5qbG9mx408sXn4t1bvOIxx+iJyc3vNssYhId3HUxSLNbLKZVQFvRvdPMbMH416ZvMuxzCwX6e3MQuzdu5Q1a77GX+q+x6sNNxz+P22NjbODLk9ERNqIZfXyHwHnAtsB3H0x8KF4FiXtKy7+xlFHdnJzz9C6iiIc8XjLvgnAO+8kKJSKiCSOmNrpuPvGIw51PMNARCRgnc2mVygVEUk8sQTSjWY2BXAzSzGzrxG9fS8ikoj0eIuISPcSyyz7a4D/AgYBtcBLwJfjWZSIyPuhxgkiIt1Lp4HUIr0l/8XdL+uiekRERESkl+n0lr27twJTu6gWEREREemFYrll/6qZPQA8CRxeh9TdF8atKhERERHpNWIJpFOif97V5pgDZx7/ckRERESkt4mlU5Oe+hcRERGRuImlU9N3zSynzX6umf1HfMsSERERkd4ilnVIz3f3nYd23L0RuCB+JYmIiIhIbxJLIA2ZWeqhHTNLB1I7OV9EREREJGaxTGr6b+BvZvYrIpOZrgQei2tVIiIiItJrxDKpaYaZLQHOBgz4jru/GPfKRERERKRXiGWEFCK961vc/a9m1sfMsty9KZ6FiYiIiEjvEMss+38DngF+Fj00CHg+nkWJiIiISO8Ry6SmLwOnA7sB3H0VUBTPokRERESk94glkO539wOHdswsmcjkJhERERGR9y2WQPqKmX0TSDezjwJPA3+Ib1kiIiIi0lvEEkhvBhqApcD/A14AvhXPokRERESk94hl2aeDZvY88Ly7N3RBTSIiIiLSi3Q4QmoRd5jZNmAFUG1mDWb27a4rT0RERER6us5u2V9PZHZ9ubvnu3secBpwupl9tUuqExEREZEer7NA+q/AdHdfd+iAu68FLo++JiIiIiLyvnUWSMPuvu3Ig9HnSMPxK0lEREREepPOAumB9/iaiIiIiEjMOptlf4qZ7W7nuAFpcapHRERERHqZDgOpu4e6shARERER6Z1iWRhfRERERCRuFEhFREREJFBxDaRmdp6ZVZvZajO7uZPzPmNmbmYT41mPiIiIiCSeuAVSMwsBPwHOB8qA6WZW1s55WcBXgLnxqkVEREREElc8R0grgNXuvtbdDwAzgantnPcdYAbwdhxrEREREZEEFc9AOgjY2Ga/NnrsMDMbBwxx9z/GsQ4RERERSWDxDKTWzjE//KJZEvBD4MajXsjsajObb2bzGxoajmOJIiIiIhK0eAbSWmBIm/3BwKY2+1nAScDLZrYemATMam9ik7s/7O4T3X1iYWFhHEsWERERka4Wz0A6Dyg1s2FmlgJMA2YdetHdd7l7gbuXuHsJ8BrwCXefH8eaRERERCTBxC2QunsLcC3wIvAm8JS7Lzezu8zsE/H6XBERERHpXjrrZf++ufsLwAtHHPt2B+d+JJ61iIiIiEhiUqcmEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFBxDaRmdp6ZVZvZajO7uZ3XbzCzKjNbYmZ/M7Oh8axHRERERBJP3AKpmYWAnwDnA2XAdDMrO+K0RcBEdz8ZeAaYEa96RERERCQxxXOEtAJY7e5r3f0AMBOY2vYEd5/t7m9Fd18DBsexHhERERFJQPEMpIOAjW32a6PHOvIF4M/tvWBmV5vZfDOb39DQcBxLFBEREZGgxTOQWjvHvN0TzS4HJgL3tPe6uz/s7hPdfWJhYeFxLFFEREREgpYcx2vXAkPa7A8GNh15kpmdDdwKfNjd98exHhERERFJQPEcIZ0HlJrZMDNLAaYBs9qeYGbjgJ8Bn3D3+jjWIiIiIiIJKm6B1N1bgGuBF4E3gafcfbmZ3WVmn4iedg+QCTxtZm+Y2awOLiciIiIiPVQ8b9nj7i8ALxxx7Nttts+O5+eLiIiISOJTpyYRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKAUSEVEREQkUAqkIiIiIhIoBVIRERERCZQCqYiIiIgESoFURERERAKlQCoiIiIigVIgFREREZFAKZCKiIiISKDiGkjN7Dwzqzaz1WZ2czuvp5rZk9HX55pZSTzrEREREZHEE7dAamYh4CfA+UAZMN3Myo447QtA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\n",
"text/plain": [
"<Figure size 720x504 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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MCIiIr2u23d3dy/t0aNH7uLFi126du1aCADjxo1rl5WVZb1ixYpDVX3O2MRv+nrJkiXOv/76q/O2bdvSnJ2dy+Li4oILCgoM5vKbcnJyKjP+X0qJBQsWHIyKiioyzXPLLbcU9uzZ8/IPP/zg0r9//6Dp06cfGThwYLVdFlhDSkRERFRHxmA0LGwefH3/fbVP6ZUrm2oda508edI6KyvLCgDy8vLE2rVrW4aGhhYCwHvvvee+Zs0al0WLFmVaWVlVuY4NGza0PHPmjFVeXp74+eefW/Xq1SsvOzvbysXFpdTZ2bls586d9qmpqS0A4Lbbbru8adMm59OnT1sVFRWJH374ocoq3sTExJx3333Xs6xMxai//fabAwDs37/fNjQ0tGjChAln+/btm71r1y6Hmuwra0iJiIiI6sA0GHV1TQRQPtBp9+4h9llZns61Gdh0/Phxm9GjR/uWlpZCSikGDRp04b777rsEAC+++GKndu3aFcXGxoYCQFJS0sUpU6acqryO2NjYvOHDh/seOXLEfujQoedvu+22/IKCgoIZM2Z4BAUFhfn7+xdGRUVdBoBOnToVv/TSSycTEhJCPTw8ijt37pxfWlpqtsr07bffPvnYY491DAkJCZNSCm9v76KUlJSDX3/9tdv8+fNbW1tbSw8Pj+K33nrrZE32lQEpERERUS2ZC0aNXF0T4ez8n8K0tFF+tZn6KT4+vuCPP/7Yby6tpKRke03W4e7uXjJr1qxjpu85ODjIdevWZZjL/+yzz55/9tlnz1d+f+HChUdMXzs5Oclvv/32aOV8b7311um33nrrdE3KZopN9kRERES1lJu71WwwamRrm1AWEjIrMydns2MjF61ZYQ0pERERUS117PhitXnc3ZNzazsXaV2MHTv2PIBrajubItaQEhEREZGuGJASERERmSGhpjei+lNWViYAlFV+nwEpERERkRnn8stw/vx5BqX1pKysTJw7d84FwN7KaexDSkRERGTG0kNFiOmUi3PnztV6HadPn7YuLS11rz7nTaEMwN6SkpJHKicwICUiIiIyI78E8PX1rdM6wsLC9kgpY+upSDcsNtkTERERka4YkBIRERGRrhiQEhEREZGuGJASERERka4YkBIRERGRrhiQEhEREZGuGJASERERka4YkBIRERGRrhiQEhEREZGuGJASERERka4YkBIRERGR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\n",
"text/plain": [
"<Figure size 720x504 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"for dist in [1,2]:\n",
" v1 = grouped_aggL.loc[(0,dist,100.0,slice(None))]\n",
" v2 = grouped_aggL.loc[(1,dist,100.0,slice(None))]\n",
" aux_aggL = v1['Ti'].values / v2['Ti'].values\n",
"\n",
" colors = ['r', 'orange', 'g', 'm', 'y']\n",
" markers = ['+', 'x', '1', '2', 'X']\n",
"\n",
" f=plt.figure(figsize=(10, 7))\n",
" ax1 = f.add_subplot(111)\n",
" plt.xlim(0, max(values)+1)\n",
" plt.ylim(0, 1.2)\n",
" plt.xticks(values)\n",
" ax1.set_ylabel('Decremento velocidad')\n",
" ax1.set_xlabel('Procesos hijo')\n",
" ax1.set_title(\"Aumento de velocidad en las iteraciones al realizar redistribuciones asíncronas\")\n",
"\n",
"\n",
" for i in range(len(values)):\n",
" numP = values[i]\n",
" c = colors[i]\n",
" \n",
" mini = i * (len(values)-1)\n",
" maxi = (i+1) * (len(values)-1)\n",
" array_values = aux_aggL[mini:maxi]\n",
" indexes = np.arange(len(values)-1)\n",
" aux_j=0\n",
" for j in range(len(values)):\n",
" if(values[j] != numP):\n",
" indexes[aux_j] = values[j]\n",
" aux_j+=1\n",
" \n",
" x = indexes\n",
" y = array_values\n",
" label = str(numP) + ' padres'\n",
" ax1.axvline(numP)\n",
" plt.plot(x, y, color=colors[i], label=label, marker=markers[1], markersize=10)\n",
" \n",
" ax1.axhline(1, color='k')\n",
" f.legend()\n",
" #f.tight_layout()\n",
" f.savefig(\"Images/\"+\"Iters\"+ dist_names[dist] +\"_SpeedUp\", format=\"png\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"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.7.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
%% Cell type:code id: tags:
``` python
%matplotlib inline
import pandas as pd
from pandas import DataFrame, Series
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
import sys
```
%% Cell type:code id: tags:
``` python
matrixMalEX="data_GG.csv"
matrixMal="data_GM.csv"
matrixIt="data_L.csv"
n_qty=2 #CAMBIAR SEGUN LA CANTIDAD DE NODOS USADOS
repet = 3 * 2 #CAMBIAR EL PRIMER NUMERO SEGUN NUMERO DE EJECUCIONES POR CONFIG
p_value = 0.05
values = [2, 4, 8, 16, 32]
dist_names = ['null', 'BestFit', 'WorstFit']
```
%% Cell type:code id: tags:
``` python
def speedUp(arr, seq, df):
numP = df.loc[arr.index[0]].NP
return seq[( seq.NP == numP )]['EX'] / arr.mean()
```
%% Cell type:code id: tags:
``` python
dfG = pd.read_csv( matrixMalEX )
dfG = dfG.drop(columns=dfG.columns[0])
dfG['S'] = dfG['N']
dfG['N'] = dfG['S'] + dfG['%Async']
dfG['%Async'] = (dfG['%Async'] / dfG['N']) * 100
if(n_qty == 1):
group = dfG.groupby(['%Async', 'Groups'])['TE']
else:
group = dfG.groupby(['Dist', '%Async', 'Groups'])['TE']
#group
grouped_aggG = group.agg(['mean'])
grouped_aggG.rename(columns={'mean':'TE',}, inplace=True)
```
%% Cell type:code id: tags:
``` python
from natsort import index_natsorted
grouped_aggG.sort_values(
by="Groups",
key=lambda x: np.argsort(index_natsorted(df["Groups"]))
)
grouped_aggG
```
%% Cell type:code id: tags:
``` python
dfM = pd.read_csv( matrixMal )
dfM = dfM.drop(columns=dfM.columns[0])
dfM['S'] = dfM['N']
dfM['N'] = dfM['S'] + dfM['%Async']
dfM["TR"] = dfM["TC"] + dfM["TS"] + dfM["TA"]
dfM['%Async'] = (dfM['%Async'] / dfM['N']) * 100
if(n_qty == 1):
groupM = dfM.groupby(['%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']
else:
groupM = dfM.groupby(['Dist', '%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']
#group
grouped_aggM = groupM.agg(['mean'])
grouped_aggM.columns = grouped_aggM.columns.get_level_values(0)
```
%% Cell type:code id: tags:
``` python
dfL = pd.read_csv( matrixIt )
dfL = dfL.drop(columns=dfL.columns[0])
dfL['S'] = dfL['N']
dfL['N'] = dfL['S'] + dfL['%Async']
dfL['%Async'] = (dfL['%Async'] / dfL['N']) * 100
if(n_qty == 1):
groupL = dfL[dfL['NS'] != 0].groupby(['Tt', '%Async', 'NP', 'NS'])['Ti', 'To']
else:
groupL = dfL[dfL['NS'] != 0].groupby(['Tt', 'Dist', '%Async', 'NP', 'NS'])['Ti', 'To']
#group
grouped_aggL = groupL.agg(['mean', 'count'])
grouped_aggL.columns = grouped_aggL.columns.get_level_values(0)
grouped_aggL.set_axis(['Ti', 'Iters', 'To', 'Iters2'], axis='columns')
grouped_aggL['Iters'] = np.ceil(grouped_aggL['Iters']/6) # TODO Cambiar a repeticiones realizadas
grouped_aggL['Iters2'] = np.ceil(grouped_aggL['Iters2']/6)
```
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: FutureWarning: set_axis currently defaults to operating inplace.
This will change in a future version of pandas, use inplace=True to avoid this warning.
app.launch_new_instance()
%% Cell type:code id: tags:
``` python
grouped_aggL.to_excel("resultL.xlsx")
grouped_aggM.to_excel("resultM.xlsx")
grouped_aggG.to_excel("resultG.xlsx")
```
%% Cell type:code id: tags:
``` python
dfG
```
%%%% Output: execute_result
N %Async Groups Dist Matrix Time Iters TE \
0 1000000000 0.0 8,32 2,2 100000 0.1 1000 31.525710
1 1000000000 0.0 8,32 2,2 100000 0.1 1000 33.315857
2 1000000000 0.0 8,32 2,2 100000 0.1 1000 33.347537
3 1000000000 75.0 4,32 1,1 100000 0.1 1000 57.219027
4 1000000000 75.0 4,32 1,1 100000 0.1 1000 55.469166
.. ... ... ... ... ... ... ... ...
595 1000000000 50.0 4,8 2,2 100000 0.1 1000 73.771357
596 1000000000 50.0 4,8 2,2 100000 0.1 1000 75.557508
597 1000000000 50.0 16,8 1,1 100000 0.1 1000 35.949913
598 1000000000 50.0 16,8 1,1 100000 0.1 1000 37.900348
599 1000000000 50.0 16,8 1,1 100000 0.1 1000 36.012772
S
0 1000000000
1 1000000000
2 1000000000
3 250000000
4 250000000
.. ...
595 500000000
596 500000000
597 500000000
598 500000000
599 500000000
[600 rows x 9 columns]
%% Cell type:code id: tags:
``` python
grouped_aggG
```
%%%% Output: execute_result
TE
Dist %Async Groups
1,1 0.0 16,2 112.087769
16,32 18.394706
16,4 61.887052
16,8 37.986463
2,16 113.187865
... ...
2,2 100.0 4,8 74.864688
8,16 37.999586
8,2 123.584176
8,32 31.730297
8,4 74.052463
[200 rows x 1 columns]
%% Cell type:code id: tags:
``` python
dfM
```
%%%% Output: execute_result
N %Async NP NS Dist Matrix Time Iters TC TS \
0 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.341434 0.695848
1 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.405911 0.639849
2 1000000000 0.0 8 32 2,2 100000 0.1 1000 1.346017 0.747863
3 1000000000 75.0 4 32 1,1 100000 0.1 1000 0.688062 0.064900
4 1000000000 75.0 4 32 1,1 100000 0.1 1000 0.702200 0.068039
.. ... ... .. .. ... ... ... ... ... ...
595 1000000000 50.0 4 8 2,2 100000 0.1 1000 0.390444 0.142287
596 1000000000 50.0 4 8 2,2 100000 0.1 1000 0.351690 0.154699
597 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.337472 0.081077
598 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.351262 0.103176
599 1000000000 50.0 16 8 1,1 100000 0.1 1000 0.349151 0.094121
TA S TR
0 0.000000 1000000000 2.037282
1 0.000000 1000000000 2.045760
2 0.000000 1000000000 2.093880
3 0.364941 250000000 1.117903
4 0.412072 250000000 1.182311
.. ... ... ...
595 0.338576 500000000 0.871307
596 0.354917 500000000 0.861306
597 0.243481 500000000 0.662030
598 0.261565 500000000 0.716003
599 0.221750 500000000 0.665022
[600 rows x 13 columns]
%% Cell type:code id: tags:
``` python
grouped_aggM
```
%%%% Output: execute_result
TC TS TA TR
Dist %Async NP NS
1,1 0.0 2 4 0.220380 0.314893 0.000000 0.535273
8 0.248143 0.375003 0.000000 0.623146
16 0.339042 0.486650 0.000000 0.825692
32 0.743840 0.506385 0.000000 1.250225
4 2 0.197858 0.311136 0.000000 0.508994
... ... ... ... ...
2,2 100.0 16 32 1.358891 0.000000 1.419016 2.777907
32 2 0.591882 0.000000 2.477300 3.069183
4 0.804965 0.000000 1.729638 2.534603
8 0.935128 0.000000 1.520682 2.455810
16 1.221248 0.000000 1.541904 2.763152
[200 rows x 4 columns]
%% Cell type:code id: tags:
``` python
dfL
```
%%%% Output: execute_result
N %Async NP N_par NS Dist Matrix Time Iters \
0 1000000000 0.0 32 8 0 2 100000 0.1 1000
1 1000000000 0.0 32 8 0 2 100000 0.1 1000
2 1000000000 0.0 32 8 0 2 100000 0.1 1000
3 1000000000 0.0 32 8 0 2 100000 0.1 1000
4 1000000000 0.0 32 8 0 2 100000 0.1 1000
... ... ... .. ... .. ... ... ... ...
1199995 1000000000 50.0 8 16 0 1 100000 0.1 1000
1199996 1000000000 50.0 8 16 0 1 100000 0.1 1000
1199997 1000000000 50.0 8 16 0 1 100000 0.1 1000
1199998 1000000000 50.0 8 16 0 1 100000 0.1 1000
1199999 1000000000 50.0 8 16 0 1 100000 0.1 1000
Ti Tt To S
0 0.005463 0.0 6.0 1000000000
1 0.005350 0.0 6.0 1000000000
2 0.005355 0.0 6.0 1000000000
3 0.005354 0.0 6.0 1000000000
4 0.005352 0.0 6.0 1000000000
... ... ... ... ...
1199995 0.024075 0.0 27.0 500000000
1199996 0.024076 0.0 27.0 500000000
1199997 0.024076 0.0 27.0 500000000
1199998 0.024411 0.0 27.0 500000000
1199999 0.024075 0.0 27.0 500000000
[1200000 rows x 13 columns]
%% Cell type:code id: tags:
``` python
grouped_aggL
```
%%%% Output: execute_result
Ti Iters To Iters2
Tt Dist %Async NP NS
0.0 1 0.0 2 4 0.099861 500.0 112.000000 500.0
8 0.099849 500.0 112.000000 500.0
16 0.099860 500.0 112.000000 500.0
32 0.099853 500.0 112.000000 500.0
4 2 0.049642 500.0 55.666667 500.0
... ... ... ... ...
1.0 2 100.0 16 32 0.034899 21.0 14.000000 21.0
32 2 0.012084 101.0 7.000000 101.0
4 0.015599 54.0 7.000000 54.0
8 0.012685 54.0 7.000000 54.0
16 0.015421 44.0 7.000000 44.0
[360 rows x 4 columns]
%% Cell type:code id: tags:
``` python
print("TIEMPO EJECUCCION")
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
if numP != numC:
group = str(numP) + "," + str(numC)
v1 = dfG[(dfG["%Async"] == 0.0)][(dfG.Groups == group)][(dfG["Dist"] == dist_v)]['TE']
v2 = dfG[(dfG["%Async"] == 100.0)][(dfG.Groups == group)][(dfG["Dist"] == dist_v)]['TE']
res = stats.ttest_ind(v1, v2)
diff = grouped_aggG['TE'].loc[(dist_v, 0.0, group)] - grouped_aggG['TE'].loc[(dist_v, 100.0, group)]
if diff > 0:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
if res[1] < p_value:
print("EX numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,3)), mejor)
```
%%%% Output: stream
TIEMPO EJECUCCION
Distribución BestFit -------------------------
Para 2 padres
EX numC= 4 p = 0.039 Diff = 0.09 Asíncrono
Para 4 padres
Para 8 padres
EX numC= 4 p = 0.0 Diff = 1.411 Síncrono
Para 16 padres
EX numC= 2 p = 0.014 Diff = 3.662 Asíncrono
Para 32 padres
EX numC= 4 p = 0.002 Diff = 4.589 Asíncrono
Distribución WorstFit -------------------------
Para 2 padres
Para 4 padres
EX numC= 16 p = 0.046 Diff = 0.304 Síncrono
EX numC= 32 p = 0.012 Diff = 0.542 Síncrono
Para 8 padres
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# Remove the CWD from sys.path while we load stuff.
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# This is added back by InteractiveShellApp.init_path()
%%%% Output: stream
Para 16 padres
EX numC= 2 p = 0.023 Diff = 6.349 Asíncrono
EX numC= 4 p = 0.0 Diff = 1.799 Asíncrono
EX numC= 8 p = 0.046 Diff = 0.261 Asíncrono
Para 32 padres
EX numC= 2 p = 0.01 Diff = 18.514 Asíncrono
EX numC= 4 p = 0.0 Diff = 4.454 Asíncrono
EX numC= 8 p = 0.003 Diff = 1.92 Asíncrono
%% Cell type:code id: tags:
``` python
print("TIEMPO MALLEABILITY")
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
if numP != numC:
v1 = dfM[(dfM["%Async"] == 0.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM["Dist"] == dist_v)]['TS']
v2 = dfM[(dfM["%Async"] == 100.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM["Dist"] == dist_v)]['TA']
res = stats.ttest_ind(v1, v2)
diff = grouped_aggM['TS'].loc[(dist_v, 0.0, numP, numC)] - grouped_aggM['TA'].loc[(dist_v, 100.0, numP, numC)]
if diff > 0:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
if res[1] < p_value:
print("TR numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,3)), mejor)
```
%%%% Output: stream
TIEMPO MALLEABILITY
Distribución 1 -------------------------
Para 2 padres
TR numC= 8 p = 0.0 Diff = 0.029 Síncrono
Para 4 padres
TR numC= 8 p = 0.006 Diff = 0.043 Síncrono
TR numC= 32 p = 0.025 Diff = 0.052 Síncrono
Para 8 padres
TR numC= 4 p = 0.016 Diff = 0.022 Asíncrono
TR numC= 16 p = 0.009 Diff = 0.031 Síncrono
TR numC= 32 p = 0.0 Diff = 0.483 Síncrono
Para 16 padres
TR numC= 8 p = 0.002 Diff = 0.072 Síncrono
TR numC= 32 p = 0.019 Diff = 0.549 Síncrono
Para 32 padres
TR numC= 4 p = 0.002 Diff = 0.981 Síncrono
TR numC= 8 p = 0.001 Diff = 0.972 Síncrono
TR numC= 16 p = 0.001 Diff = 0.831 Síncrono
Distribución 2 -------------------------
Para 2 padres
TR numC= 4 p = 0.0 Diff = 0.069 Síncrono
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
if __name__ == '__main__':
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# Remove the CWD from sys.path while we load stuff.
%%%% Output: stream
TR numC= 8 p = 0.029 Diff = 0.035 Síncrono
Para 4 padres
TR numC= 8 p = 0.02 Diff = 0.031 Síncrono
TR numC= 32 p = 0.009 Diff = 0.601 Síncrono
Para 8 padres
TR numC= 16 p = 0.011 Diff = 0.729 Síncrono
TR numC= 32 p = 0.018 Diff = 0.423 Síncrono
Para 16 padres
TR numC= 4 p = 0.001 Diff = 0.884 Síncrono
TR numC= 32 p = 0.021 Diff = 0.36 Síncrono
Para 32 padres
TR numC= 2 p = 0.029 Diff = 1.548 Síncrono
TR numC= 4 p = 0.008 Diff = 0.84 Síncrono
TR numC= 8 p = 0.011 Diff = 0.726 Síncrono
TR numC= 16 p = 0.004 Diff = 0.606 Síncrono
%% Cell type:code id: tags:
``` python
print("TIEMPO Iters")
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
if numP != numC:
#exp = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == 1)][(dfL["%Async"] == 0.0)][(dfL.NP == numP)][(dfL.NS == numC)]
#TimeOp = exp['Ti']
#print(TimeOp)
v1 = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == dist)][(dfL["%Async"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']
v2 = dfL[(dfL["Tt"] == 1)][(dfL["Dist"] == dist)][(dfL["%Async"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']
res = stats.ttest_ind(v1, v2, equal_var = False)
diff = grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)] - grouped_aggL['Ti'].loc[(1, dist, 100.0, numP, numC)]
if diff > 0:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
if res[1] < p_value:
#and abs(diff) > grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)]
print("Ti numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,4)), mejor)
```
%%%% Output: stream
TIEMPO Iters
Distribución BestFit -------------------------
Para 2 padres
Ti numC= 4 p = 0.035 Diff = 0.0001 Síncrono
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
if sys.path[0] == '':
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
del sys.path[0]
%%%% Output: stream
Ti numC= 8 p = 0.025 Diff = 0.0001 Síncrono
Ti numC= 16 p = 0.002 Diff = 0.0001 Síncrono
Ti numC= 32 p = 0.007 Diff = 0.0001 Síncrono
Para 4 padres
Ti numC= 16 p = 0.0 Diff = 0.0006 Síncrono
Para 8 padres
Ti numC= 4 p = 0.0 Diff = 0.0009 Síncrono
Ti numC= 32 p = 0.007 Diff = 0.0029 Síncrono
Para 16 padres
Ti numC= 32 p = 0.0 Diff = 0.0097 Síncrono
Para 32 padres
Ti numC= 2 p = 0.0 Diff = 0.0029 Síncrono
Ti numC= 4 p = 0.0 Diff = 0.0056 Síncrono
Ti numC= 8 p = 0.0 Diff = 0.0055 Síncrono
Ti numC= 16 p = 0.0 Diff = 0.0053 Síncrono
Distribución WorstFit -------------------------
Para 2 padres
Ti numC= 32 p = 0.024 Diff = 0.0256 Síncrono
Para 4 padres
Ti numC= 16 p = 0.0 Diff = 0.0243 Síncrono
Ti numC= 32 p = 0.0 Diff = 0.0343 Síncrono
Para 8 padres
Ti numC= 4 p = 0.036 Diff = 0.0044 Síncrono
Ti numC= 16 p = 0.0 Diff = 0.008 Síncrono
Ti numC= 32 p = 0.0 Diff = 0.0225 Síncrono
Para 16 padres
Ti numC= 2 p = 0.0 Diff = 0.0067 Síncrono
Ti numC= 4 p = 0.0 Diff = 0.0092 Síncrono
Ti numC= 8 p = 0.0 Diff = 0.0098 Síncrono
Ti numC= 32 p = 0.0 Diff = 0.0224 Síncrono
Para 32 padres
Ti numC= 2 p = 0.0 Diff = 0.0058 Síncrono
Ti numC= 4 p = 0.0 Diff = 0.0094 Síncrono
Ti numC= 8 p = 0.0 Diff = 0.0064 Síncrono
Ti numC= 16 p = 0.0 Diff = 0.0092 Síncrono
%% Cell type:code id: tags:
``` python
iters = dfM['Iters'].mean()
resultados = [0,0]
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
if numP != numC:
Titer = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == dist)][(dfL.NP == numC)]['Ti'].mean() #Tiempo por iteracion
i=0
for adr in [0.0, 100.0]:
auxExp = dfM[(dfM["Dist"] == dist_v)][(dfM["%Async"] == adr)][(dfM.NP == numP)][(dfM.NS == numC)]
Tr = auxExp['TS'].mean() + auxExp['TA'].mean() #Tiempo de redistribucion
M_it = dfL[(dfL["Tt"] == 1)][(dfL["Dist"] == dist)][(dfL["%Async"] == adr)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti'].count()/3 #Iteraciones asincronas
#No se presupone una diferencia temporal entre iteraciones sincronas y asincronas
if(M_it > iters):
M_it = iters
resultados[i] = (iters - M_it) * Titer + Tr
i+=1
#print(M_it)
#print(Titer)
#print((iters - M_it) * Titer)
#print(Tr)
#print("End")
if resultados[0] > resultados[1]:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
diff = abs(round(resultados[0] - resultados[1], 3))
print("NC="+ str(numC) + " Es mejor " + mejor + " con una diff de "+ str(diff))
#TODO Comprobar
```
%%%% Output: stream
Distribución BestFit -------------------------
Para 2 padres
NC=4 Es mejor Asíncrono con una diff de 0.123
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# Remove the CWD from sys.path while we load stuff.
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
app.launch_new_instance()
%%%% Output: stream
NC=8 Es mejor Asíncrono con una diff de 0.07
NC=16 Es mejor Asíncrono con una diff de 0.046
NC=32 Es mejor Asíncrono con una diff de 0.014
Para 4 padres
NC=2 Es mejor Asíncrono con una diff de 0.645
NC=8 Es mejor Asíncrono con una diff de 0.13
NC=16 Es mejor Asíncrono con una diff de 0.052
NC=32 Es mejor Síncrono con una diff de 0.005
Para 8 padres
NC=2 Es mejor Asíncrono con una diff de 1.523
NC=4 Es mejor Asíncrono con una diff de 0.354
NC=16 Es mejor Asíncrono con una diff de 0.066
NC=32 Es mejor Síncrono con una diff de 0.327
Para 16 padres
NC=2 Es mejor Asíncrono con una diff de 3.676
NC=4 Es mejor Asíncrono con una diff de 1.235
NC=8 Es mejor Asíncrono con una diff de 0.406
NC=32 Es mejor Síncrono con una diff de 0.304
Para 32 padres
NC=2 Es mejor Asíncrono con una diff de 16.171
NC=4 Es mejor Asíncrono con una diff de 4.551
NC=8 Es mejor Asíncrono con una diff de 1.599
NC=16 Es mejor Asíncrono con una diff de 0.12
Distribución WorstFit -------------------------
Para 2 padres
NC=4 Es mejor Asíncrono con una diff de 0.13
NC=8 Es mejor Asíncrono con una diff de 0.064
NC=16 Es mejor Asíncrono con una diff de 0.034
NC=32 Es mejor Síncrono con una diff de 0.151
Para 4 padres
NC=2 Es mejor Asíncrono con una diff de 0.637
NC=8 Es mejor Asíncrono con una diff de 0.142
NC=16 Es mejor Síncrono con una diff de 0.28
NC=32 Es mejor Síncrono con una diff de 0.499
Para 8 padres
NC=2 Es mejor Asíncrono con una diff de 1.575
NC=4 Es mejor Asíncrono con una diff de 0.344
NC=16 Es mejor Síncrono con una diff de 0.32
NC=32 Es mejor Síncrono con una diff de 0.278
Para 16 padres
NC=2 Es mejor Asíncrono con una diff de 6.404
NC=4 Es mejor Asíncrono con una diff de 1.803
NC=8 Es mejor Asíncrono con una diff de 0.308
NC=32 Es mejor Síncrono con una diff de 0.113
Para 32 padres
NC=2 Es mejor Asíncrono con una diff de 18.438
NC=4 Es mejor Asíncrono con una diff de 4.533
NC=8 Es mejor Asíncrono con una diff de 1.927
NC=16 Es mejor Asíncrono con una diff de 0.481
%% Cell type:code id: tags:
``` python
grouped_aggL
```
%%%% Output: execute_result
Ti Iters To Iters2
Tt Dist %Async NP NS
0.0 1 0.0 2 4 0.099861 500.0 112.000000 500.0
8 0.099849 500.0 112.000000 500.0
16 0.099860 500.0 112.000000 500.0
32 0.099853 500.0 112.000000 500.0
4 2 0.049642 500.0 55.666667 500.0
... ... ... ... ...
1.0 2 100.0 16 32 0.034899 21.0 14.000000 21.0
32 2 0.012084 101.0 7.000000 101.0
4 0.015599 54.0 7.000000 54.0
8 0.012685 54.0 7.000000 54.0
16 0.015421 44.0 7.000000 44.0
[360 rows x 4 columns]
%% Cell type:code id: tags:
``` python
for dist in [1,2]:
v1 = grouped_aggL.loc[(0,dist,100.0,slice(None))]
v2 = grouped_aggL.loc[(1,dist,100.0,slice(None))]
aux_aggL = v1['Ti'].values / v2['Ti'].values
colors = ['r', 'orange', 'g', 'm', 'y']
markers = ['+', 'x', '1', '2', 'X']
f=plt.figure(figsize=(10, 7))
ax1 = f.add_subplot(111)
plt.xlim(0, max(values)+1)
plt.ylim(0, 1.2)
plt.xticks(values)
ax1.set_ylabel('Decremento velocidad')
ax1.set_xlabel('Procesos hijo')
ax1.set_title("Aumento de velocidad en las iteraciones al realizar redistribuciones asíncronas")
for i in range(len(values)):
numP = values[i]
c = colors[i]
mini = i * (len(values)-1)
maxi = (i+1) * (len(values)-1)
array_values = aux_aggL[mini:maxi]
indexes = np.arange(len(values)-1)
aux_j=0
for j in range(len(values)):
if(values[j] != numP):
indexes[aux_j] = values[j]
aux_j+=1
x = indexes
y = array_values
label = str(numP) + ' padres'
ax1.axvline(numP)
plt.plot(x, y, color=colors[i], label=label, marker=markers[1], markersize=10)
ax1.axhline(1, color='k')
f.legend()
#f.tight_layout()
f.savefig("Images/"+"Iters"+ dist_names[dist] +"_SpeedUp", format="png")
```
%%%% Output: display_data
[Hidden Image Output]
%%%% Output: display_data
[Hidden Image Output]
%% Cell type:code id: tags:
``` python
```
import sys
import glob
import numpy as np
import pandas as pd
def getData(lineS, outData, tp, hasIter = False):
for data in lineS:
k_v = data.split('=')
if k_v[0] == "time":
time = float(k_v[1])
elif k_v[0] == "iters" and hasIter:
iters = int(k_v[1])
outData[tp] = time
if hasIter:
outData[tp+1] = iters
#-----------------------------------------------
def record(f, observation, line):
# Record first line - General info
lineS = line.split()
for j in range(1,7):
observation[j] = int(lineS[j].split('=')[1])
# Record procces number
line = next(f)
lineS = line.split()
j = 7
for key_values in lineS:
k_v = key_values.split('=')
observation[j] = int(k_v[1])
j+=1
# Record data
j = 9
for j in range(9, 13):
line = next(f)
lineS = line.split()
getData(lineS, observation, j)
line = next(f)
lineS = line.split()
#if observation[0] == "A":
getData(lineS, observation, 13, True)
#else:
# getData(lineS, observation, 13)
#-----------------------------------------------
def read_file(f, dataA, dataB, it):
recording = False
resizes = 0
timer = 0
previousNP = 0
for line in f:
lineS = line.split()
if len(lineS) > 0:
if lineS[0] == "Config": # CONFIG LINE
recording = True
it += 1
dataA.append([None]*8)
dataB.append([None]*11)
resizes = int(lineS[2].split('=')[1].split(',')[0])
matrix = int(lineS[3].split('=')[1].split(',')[0])
sdr = int(lineS[4].split('=')[1].split(',')[0])
adr = int(lineS[5].split('=')[1].split(',')[0]) #TODO Que lo tome como porcentaje
time = float(lineS[7].split('=')[1])
dataB[it][5] = matrix
dataB[it][0] = sdr
dataB[it][1] = adr
dataB[it][6] = time
dataB[it][4] = ""
dataA[it][4] = matrix
dataA[it][0] = sdr
dataA[it][1] = adr
dataA[it][5] = time
dataA[it][3] = ""
elif recording and resizes != 0: # RESIZE LINE
iters = int(lineS[2].split('=')[1].split(',')[0])
npr = int(lineS[3].split('=')[1].split(',')[0])
dist = lineS[5].split('=')[1]
dataB[it][7] = iters
dataA[it][6] = iters
resizes = resizes - 1
if resizes == 0:
dataB[it][3] = npr
dataB[it][4] += dist
dataA[it][3] += dist
dataA[it][2] = str(previousNP) + "," + str(npr)
timer = 3
else:
dataB[it][2] = npr
dataB[it][4] += dist + ","
dataA[it][3] += dist + ","
previousNP = npr
else: # SAVE TIMES
if timer == 3:
dataB[it][8] = float(lineS[1])
elif timer == 2:
dataB[it][9] = float(lineS[1])
elif timer == 1:
dataB[it][10] = float(lineS[1])
else:
dataA[it][7] = float(lineS[1])
timer = timer - 1
return it
#columnsA1 = ["N", "%Async", "Groups", "Dist", "Matrix", "Time", "Iters", "TE"] #7
#columnsB1 = ["N", "%Async", "NP", "NS", "Dist", "Matrix", "Time", "Iters", "TC", "TS", "TA"] #10
#Config loaded: resizes=2, matrix=1000, sdr=1000000000, adr=0, aib=0, time=2.000000 || grp=1
#Resize 0: Iters=100, Procs=2, Factors=1.000000, Phy=2
#Resize 1: Iters=100, Procs=4, Factors=0.500000, Phy=2
#Tspawn: 0.249393
#Tsync: 0.330391
#Tasync: 0
#Tex: 301.428615
#-----------------------------------------------
if len(sys.argv) < 2:
print("The files name is missing\nUsage: python3 iterTimes.py resultsName directory csvOutName")
exit(1)
if len(sys.argv) >= 3:
BaseDir = sys.argv[2]
print("Searching in directory: "+ BaseDir)
else:
BaseDir = sys.argv[2]
if len(sys.argv) >= 4:
print("Csv name will be: " + sys.argv[3] + ".csv")
name = sys.argv[3]
else:
name = "data"
insideDir = "Run"
lista = glob.glob("./" + BaseDir + insideDir + "*/" + sys.argv[1]+ "*Global.o*")
print("Number of files found: "+ str(len(lista)));
it = -1
dataA = []
dataB = []
columnsA = ["N", "%Async", "Groups", "Dist", "Matrix", "Time", "Iters", "TE"] #7
columnsB = ["N", "%Async", "NP", "NS", "Dist", "Matrix", "Time", "Iters", "TC", "TS", "TA"] #10
for elem in lista:
f = open(elem, "r")
it = read_file(f, dataA, dataB, it)
f.close()
#print(data)
dfA = pd.DataFrame(dataA, columns=columnsA)
dfA.to_csv(name + '_G.csv')
dfB = pd.DataFrame(dataB, columns=columnsB)
dfB.to_csv(name + '_M.csv')
import sys
import glob
import numpy as np
import pandas as pd
#-----------------------------------------------
def read_file(f, data, it):
matrix = 0
sdr = 0
adr = 0
time = 0
recording = False
it_line = 0
aux_it = 0
iters = 0
np = 0
np_par = 0
ns = 0
for line in f:
lineS = line.split()
if len(lineS) > 1:
if recording:
aux_it = 0
if it_line==0:
lineS.pop(0)
for observation in lineS:
data.append([None]*11)
data[it+aux_it][0] = sdr
data[it+aux_it][1] = adr
data[it+aux_it][2] = np
data[it+aux_it][3] = np_par
data[it+aux_it][4] = ns
data[it+aux_it][5] = matrix
data[it+aux_it][6] = time
data[it+aux_it][7] = iters
data[it+aux_it][8] = float(observation)
aux_it+=1
it_line = it_line + 1
elif it_line==1:
lineS.pop(0)
for observation in lineS:
data[it+aux_it][9] = float(observation)
aux_it+=1
it_line = it_line + 1
else:
lineS.pop(0)
for observation in lineS:
data[it+aux_it][10] = float(observation)
aux_it+=1
it = it + aux_it
recording = False
it_line = 0
#TODO Que tome adr como porcentaje
if lineS[0] == "Config:":
matrix = int(lineS[1].split('=')[1].split(',')[0])
sdr = int(lineS[2].split('=')[1].split(',')[0])
adr = int(lineS[3].split('=')[1].split(',')[0])
time = float(lineS[5].split('=')[1])
elif lineS[0] == "Config":
recording = True
iters = int(lineS[2].split('=')[1].split(',')[0])
np = int(lineS[5].split('=')[1].split(',')[0])
np_par = int(lineS[6].split('=')[1].split(',')[0])
ns = int(float(lineS[7].split('=')[1]))
return it
#-----------------------------------------------
#Config: matrix=1000, sdr=1000000000, adr=0, aib=0 time=2.000000
#Config Group: iters=100, factor=1.000000, phy=2, procs=2, parents=0, sons=4
#Ttype: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
if len(sys.argv) < 2:
print("The files name is missing\nUsage: python3 iterTimes.py resultsName directory csvOutName")
exit(1)
if len(sys.argv) >= 3:
BaseDir = sys.argv[2]
print("Searching in directory: "+ BaseDir)
else:
BaseDir = sys.argv[2]
if len(sys.argv) >= 4:
print("Csv name will be: " + sys.argv[3] + ".csv")
name = sys.argv[3]
else:
name = "data"
insideDir = "Run"
lista = glob.glob("./" + BaseDir + insideDir + "*/" + sys.argv[1]+ "*ID*.o*")
print("Number of files found: "+ str(len(lista)));
it = 0
data = [] #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #10
columns = ["N", "%Async", "NP", "N_par", "NS", "Matrix", "Time", "Iters", "Ti", "Tt", "To"] #11
for elem in lista:
f = open(elem, "r")
it = read_file(f, data, it)
f.close()
#print(data)
df = pd.DataFrame(data, columns=columns)
df.to_csv(name + '.csv')
import sys
import glob
import numpy as np
import pandas as pd
def getData(lineS, outData, tp, hasIter = False):
for data in lineS:
k_v = data.split('=')
if k_v[0] == "time":
time = float(k_v[1])
elif k_v[0] == "iters" and hasIter:
iters = int(k_v[1])
outData[tp] = time
if hasIter:
outData[tp+1] = iters
#-----------------------------------------------
def record(f, observation, line):
# Record first line - General info
lineS = line.split()
for j in range(1,7):
observation[j] = int(lineS[j].split('=')[1])
# Record procces number
line = next(f)
lineS = line.split()
j = 7
for key_values in lineS:
k_v = key_values.split('=')
observation[j] = int(k_v[1])
j+=1
# Record data
j = 9
for j in range(9, 13):
line = next(f)
lineS = line.split()
getData(lineS, observation, j)
line = next(f)
lineS = line.split()
#if observation[0] == "A":
getData(lineS, observation, 13, True)
#else:
# getData(lineS, observation, 13)
#-----------------------------------------------
def read_file(f, dataA, dataB, it):
recording = False
resizes = 0
timer = 0
previousNP = 0
for line in f:
lineS = line.split()
if len(lineS) > 0:
if lineS[0] == "Config": # CONFIG LINE
recording = True
it += 1
dataA.append([None]*9)
dataB.append([None]*12)
resizes = int(lineS[2].split('=')[1].split(',')[0])
compute_tam = int(lineS[3].split('=')[1].split(',')[0])
comm_tam = int(lineS[4].split('=')[1].split(',')[0])
sdr = int(lineS[5].split('=')[1].split(',')[0])
adr = int(lineS[6].split('=')[1].split(',')[0]) #TODO Que lo tome como porcentaje
# TODO Que obtenga Aib
time = float(lineS[8].split('=')[1])
dataB[it][0] = sdr
dataB[it][1] = adr
dataB[it][4] = ""
dataB[it][5] = compute_tam
dataB[it][6] = comm_tam
dataB[it][7] = time
dataB[it][8] = ""
dataA[it][0] = sdr
dataA[it][1] = adr
dataA[it][3] = ""
dataA[it][4] = compute_tam
dataA[it][5] = comm_tam
dataA[it][6] = time
dataA[it][7] = ""
elif recording and resizes != 0: # RESIZE LINE
iters = int(lineS[2].split('=')[1].split(',')[0])
npr = int(lineS[3].split('=')[1].split(',')[0])
dist = lineS[5].split('=')[1]
resizes = resizes - 1
if resizes == 0:
dataB[it][3] = npr
dataB[it][4] += dist
dataB[it][8] += str(iters)
dataA[it][2] = str(previousNP) + "," + str(npr)
dataA[it][3] += dist
dataA[it][7] += str(iters)
timer = 3
else:
dataB[it][2] = npr
dataB[it][4] += dist + ","
dataB[it][8] += str(iters) + ","
dataA[it][3] += dist + ","
dataA[it][7] += str(iters) + ","
previousNP = npr
else: # SAVE TIMES
if timer == 3:
dataB[it][9] = float(lineS[1])
elif timer == 2:
dataB[it][10] = float(lineS[1])
elif timer == 1:
dataB[it][11] = float(lineS[1])
else:
dataA[it][8] = float(lineS[1])
timer = timer - 1
return it
#columnsA1 = ["N", "%Async", "Groups", "Dist", "Matrix", "CommTam", "Time", "Iters", "TE"] #8
#columnsB1 = ["N", "%Async", "NP", "NS", "Dist", "Matrix", "CommTam", "Time", "Iters", "TC", "TS", "TA"] #11
#Config loaded: resizes=2, matrix=1000, sdr=1000000000, adr=0, aib=0, time=2.000000 || grp=1
#Resize 0: Iters=100, Procs=2, Factors=1.000000, Phy=2
#Resize 1: Iters=100, Procs=4, Factors=0.500000, Phy=2
#Tspawn: 0.249393
#Tsync: 0.330391
#Tasync: 0
#Tex: 301.428615
#-----------------------------------------------
if len(sys.argv) < 2:
print("The files name is missing\nUsage: python3 iterTimes.py resultsName directory csvOutName")
exit(1)
if len(sys.argv) >= 3:
BaseDir = sys.argv[2]
print("Searching in directory: "+ BaseDir)
else:
BaseDir = sys.argv[2]
if len(sys.argv) >= 4:
print("Csv name will be: " + sys.argv[3] + "G.csv & " + sys.argv[3] + "M.csv")
name = sys.argv[3]
else:
name = "data"
insideDir = "Run"
lista = glob.glob("./" + BaseDir + insideDir + "*/" + sys.argv[1]+ "*Global.o*")
print("Number of files found: "+ str(len(lista)));
it = -1
dataA = []
dataB = []
columnsA = ["N", "%Async", "Groups", "Dist", "Matrix", "CommTam", "Time", "Iters", "TE"] #8
columnsB = ["N", "%Async", "NP", "NS", "Dist", "Matrix", "CommTam", "Time", "Iters", "TC", "TS", "TA"] #11
for elem in lista:
f = open(elem, "r")
it = read_file(f, dataA, dataB, it)
f.close()
#print(data)
dfA = pd.DataFrame(dataA, columns=columnsA)
dfA.to_csv(name + 'G.csv')
dfB = pd.DataFrame(dataB, columns=columnsB)
dfB.to_csv(name + 'M.csv')
Esta carpeta contiene códigos para poder analizar los resultados obtenidos.
Para utilizar los códigos es necesario Python con los módulos Numpy y Pandas.
El código analyser.ipynb necesita además de la aplicación JupyterLab.
Los códigos son los siguientes:
- Malltimes.py: Recoge los tiempos globales de maleabilidad y ejecución de todos los ficheros pasados como argumento y
los almacena en dos ficheros CSV para ser utilizados en analyser.ipynb
- Itertimes.py: Recoge los tiempos locales de iteraciones de un grupo de procesos de todos los ficheros pasados como
argumento y los almacena en un fichero CSV para ser utilizado en analyser.ipynb
+ Ejemplo de uso de ambos códigos (Esperan los mismos argumentos):
python3 Malltimes.py NombreFicheros DirectorioFicheros/ NombreCSV
NombreFicheros: La parte común de los ficheros, los códigos buscan solo aquellos nombres que empiecen por esta cadena.
Por defecto, con poner "R" es suficiente.
DirectorioFicheros/: Nombre del directorio donde se encuentran todos los resultados. Esta pensado para que busque
en todos las subdirectorios que tenga en el primer nivel, pero no en segundos niveles o más.
NombreCSV: Nombre del fichero CSV en el que escribir la recopilación de resultados.
- analyser.ipynb: Código para ser ejecutado por JupyterNotebook. Dentro del mismo hay que indicar los nombres de los
ficheros CSV a analizar y tras ellos ejecutar las celdas. Como resultado se obtienen tres ficheros XLSX e imagenes
en el directorio "Images", y además varios resultados sobre T-test entre varios resultados que se reflejan como
output en la salida estandar de JupyterNotebook.
{
"cells": [
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import pandas as pd\n",
"from pandas import DataFrame, Series\n",
"import numpy as np\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"from scipy import stats\n",
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"matrixMalEX=\"data_GG.csv\"\n",
"matrixMal=\"data_GM.csv\"\n",
"matrixIt=\"data_L.csv\"\n",
"n_qty=2 #CAMBIAR SEGUN LA CANTIDAD DE NODOS USADOS\n",
"repet = 3 * 2 #CAMBIAR EL PRIMER NUMERO SEGUN NUMERO DE EJECUCIONES POR CONFIG\n",
"\n",
"p_value = 0.05\n",
"values = [2, 10, 20, 40]\n",
"dist_names = ['null', 'BestFit', 'WorstFit']"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [],
"source": [
"def speedUp(arr, seq, df):\n",
" numP = df.loc[arr.index[0]].NP\n",
" return seq[( seq.NP == numP )]['EX'] / arr.mean()"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
"dfG = pd.read_csv( matrixMalEX )\n",
"\n",
"dfG = dfG.drop(columns=dfG.columns[0])\n",
"dfG['S'] = dfG['N']\n",
"dfG['N'] = dfG['S'] + dfG['%Async']\n",
"dfG['%Async'] = (dfG['%Async'] / dfG['N']) * 100\n",
"\n",
"if(n_qty == 1):\n",
" group = dfG.groupby(['%Async', 'Groups'])['TE']\n",
"else: \n",
" group = dfG.groupby(['Dist', '%Async', 'Groups'])['TE']\n",
"\n",
"#group\n",
"grouped_aggG = group.agg(['mean'])\n",
"grouped_aggG.rename(columns={'mean':'TE',}, inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"dfM = pd.read_csv( matrixMal )\n",
"dfM = dfM.drop(columns=dfM.columns[0])\n",
"\n",
"dfM['S'] = dfM['N']\n",
"dfM['N'] = dfM['S'] + dfM['%Async']\n",
"dfM[\"TR\"] = dfM[\"TC\"] + dfM[\"TS\"] + dfM[\"TA\"]\n",
"dfM['%Async'] = (dfM['%Async'] / dfM['N']) * 100\n",
"\n",
"if(n_qty == 1):\n",
" groupM = dfM.groupby(['%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']\n",
"else:\n",
" groupM = dfM.groupby(['Dist', '%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']\n",
"\n",
"#group\n",
"grouped_aggM = groupM.agg(['mean'])\n",
"grouped_aggM.columns = grouped_aggM.columns.get_level_values(0)"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: FutureWarning: set_axis currently defaults to operating inplace.\n",
"This will change in a future version of pandas, use inplace=True to avoid this warning.\n",
" if sys.path[0] == '':\n"
]
}
],
"source": [
"dfL = pd.read_csv( matrixIt )\n",
"dfL = dfL.drop(columns=dfL.columns[0])\n",
"\n",
"if(n_qty == 1):\n",
" groupL = dfL[dfL['NS'] != 0].groupby(['Tt', '%Async', 'NP', 'NS'])['Ti', 'To']\n",
"else:\n",
" groupL = dfL[dfL['NS'] != 0].groupby(['Tt', 'Dist', '%Async', 'NP', 'NS'])['Ti', 'To']\n",
"\n",
"#group\n",
"grouped_aggL = groupL.agg(['mean', 'count'])\n",
"grouped_aggL.columns = grouped_aggL.columns.get_level_values(0)\n",
"grouped_aggL.set_axis(['Ti', 'Iters', 'To', 'Iters2'], axis='columns')\n",
"\n",
"grouped_aggL['Iters'] = np.ceil(grouped_aggL['Iters']/6) # TODO Cambiar a repeticiones realizadas\n",
"grouped_aggL['Iters2'] = np.ceil(grouped_aggL['Iters2']/6)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [],
"source": [
"grouped_aggL.to_excel(\"resultL.xlsx\") \n",
"grouped_aggM.to_excel(\"resultM.xlsx\") \n",
"grouped_aggG.to_excel(\"resultG.xlsx\") "
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>Groups</th>\n",
" <th>Dist</th>\n",
" <th>Matrix</th>\n",
" <th>CommTam</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>TE</th>\n",
" <th>S</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20,40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.325915</td>\n",
" <td>2000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20,40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.661673</td>\n",
" <td>2000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20,40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.647241</td>\n",
" <td>2000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>2000000000</td>\n",
" <td>75.0</td>\n",
" <td>10,40</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>2.710496</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2000000000</td>\n",
" <td>75.0</td>\n",
" <td>10,40</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>2.785736</td>\n",
" <td>500000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>475</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>10,10</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.292079</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>476</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>10,10</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.683571</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>477</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40,20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.107688</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>478</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40,20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.169551</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>479</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40,20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>3.442101</td>\n",
" <td>1000000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>480 rows × 10 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async Groups Dist Matrix CommTam Time Iters TE \\\n",
"0 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.325915 \n",
"1 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.661673 \n",
"2 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.647241 \n",
"3 2000000000 75.0 10,40 1,1 100000 0 0.2 1,10 2.710496 \n",
"4 2000000000 75.0 10,40 1,1 100000 0 0.2 1,10 2.785736 \n",
".. ... ... ... ... ... ... ... ... ... \n",
"475 2000000000 50.0 10,10 2,2 100000 0 0.2 1,10 1.292079 \n",
"476 2000000000 50.0 10,10 2,2 100000 0 0.2 1,10 1.683571 \n",
"477 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.107688 \n",
"478 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.169551 \n",
"479 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.442101 \n",
"\n",
" S \n",
"0 2000000000 \n",
"1 2000000000 \n",
"2 2000000000 \n",
"3 500000000 \n",
"4 500000000 \n",
".. ... \n",
"475 1000000000 \n",
"476 1000000000 \n",
"477 1000000000 \n",
"478 1000000000 \n",
"479 1000000000 \n",
"\n",
"[480 rows x 10 columns]"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfG"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>TE</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>Groups</th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1,1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td>10,10</td>\n",
" <td>7.238413</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10,2</td>\n",
" <td>7.495134</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10,20</td>\n",
" <td>1.052943</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10,40</td>\n",
" <td>2.412291</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2,10</td>\n",
" <td>1.812608</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">2,2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>20,40</td>\n",
" <td>3.978562</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40,10</td>\n",
" <td>3.869905</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40,2</td>\n",
" <td>4.056287</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40,20</td>\n",
" <td>4.384910</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40,40</td>\n",
" <td>3.143114</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>160 rows × 1 columns</p>\n",
"</div>"
],
"text/plain": [
" TE\n",
"Dist %Async Groups \n",
"1,1 0.0 10,10 7.238413\n",
" 10,2 7.495134\n",
" 10,20 1.052943\n",
" 10,40 2.412291\n",
" 2,10 1.812608\n",
"... ...\n",
"2,2 100.0 20,40 3.978562\n",
" 40,10 3.869905\n",
" 40,2 4.056287\n",
" 40,20 4.384910\n",
" 40,40 3.143114\n",
"\n",
"[160 rows x 1 columns]"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggG"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th>Dist</th>\n",
" <th>Matrix</th>\n",
" <th>CommTam</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>TC</th>\n",
" <th>TS</th>\n",
" <th>TA</th>\n",
" <th>S</th>\n",
" <th>TR</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20</td>\n",
" <td>40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.523284</td>\n",
" <td>1.571982</td>\n",
" <td>0.000000</td>\n",
" <td>2000000000</td>\n",
" <td>3.095266</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20</td>\n",
" <td>40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.395780</td>\n",
" <td>2.067917</td>\n",
" <td>0.000000</td>\n",
" <td>2000000000</td>\n",
" <td>3.463697</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>20</td>\n",
" <td>40</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.515433</td>\n",
" <td>1.939858</td>\n",
" <td>0.000000</td>\n",
" <td>2000000000</td>\n",
" <td>3.455291</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>2000000000</td>\n",
" <td>75.0</td>\n",
" <td>10</td>\n",
" <td>40</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.331821</td>\n",
" <td>0.217988</td>\n",
" <td>1.279915</td>\n",
" <td>500000000</td>\n",
" <td>2.829724</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2000000000</td>\n",
" <td>75.0</td>\n",
" <td>10</td>\n",
" <td>40</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.338515</td>\n",
" <td>0.268872</td>\n",
" <td>1.359864</td>\n",
" <td>500000000</td>\n",
" <td>2.967251</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>475</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>10</td>\n",
" <td>10</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>0.573135</td>\n",
" <td>0.091322</td>\n",
" <td>0.679278</td>\n",
" <td>1000000000</td>\n",
" <td>1.343735</td>\n",
" </tr>\n",
" <tr>\n",
" <td>476</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>10</td>\n",
" <td>10</td>\n",
" <td>2,2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>0.568495</td>\n",
" <td>0.096622</td>\n",
" <td>1.075340</td>\n",
" <td>1000000000</td>\n",
" <td>1.740457</td>\n",
" </tr>\n",
" <tr>\n",
" <td>477</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.171373</td>\n",
" <td>0.557700</td>\n",
" <td>1.843437</td>\n",
" <td>1000000000</td>\n",
" <td>3.572510</td>\n",
" </tr>\n",
" <tr>\n",
" <td>478</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.227744</td>\n",
" <td>0.634888</td>\n",
" <td>1.881406</td>\n",
" <td>1000000000</td>\n",
" <td>3.744038</td>\n",
" </tr>\n",
" <tr>\n",
" <td>479</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>1,1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1,10</td>\n",
" <td>1.101387</td>\n",
" <td>0.695218</td>\n",
" <td>2.296932</td>\n",
" <td>1000000000</td>\n",
" <td>4.093537</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>480 rows × 14 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async NP NS Dist Matrix CommTam Time Iters TC \\\n",
"0 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.523284 \n",
"1 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.395780 \n",
"2 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.515433 \n",
"3 2000000000 75.0 10 40 1,1 100000 0 0.2 1,10 1.331821 \n",
"4 2000000000 75.0 10 40 1,1 100000 0 0.2 1,10 1.338515 \n",
".. ... ... .. .. ... ... ... ... ... ... \n",
"475 2000000000 50.0 10 10 2,2 100000 0 0.2 1,10 0.573135 \n",
"476 2000000000 50.0 10 10 2,2 100000 0 0.2 1,10 0.568495 \n",
"477 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.171373 \n",
"478 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.227744 \n",
"479 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.101387 \n",
"\n",
" TS TA S TR \n",
"0 1.571982 0.000000 2000000000 3.095266 \n",
"1 2.067917 0.000000 2000000000 3.463697 \n",
"2 1.939858 0.000000 2000000000 3.455291 \n",
"3 0.217988 1.279915 500000000 2.829724 \n",
"4 0.268872 1.359864 500000000 2.967251 \n",
".. ... ... ... ... \n",
"475 0.091322 0.679278 1000000000 1.343735 \n",
"476 0.096622 1.075340 1000000000 1.740457 \n",
"477 0.557700 1.843437 1000000000 3.572510 \n",
"478 0.634888 1.881406 1000000000 3.744038 \n",
"479 0.695218 2.296932 1000000000 4.093537 \n",
"\n",
"[480 rows x 14 columns]"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfM"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>TC</th>\n",
" <th>TS</th>\n",
" <th>TA</th>\n",
" <th>TR</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1,1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"4\" valign=\"top\">2</td>\n",
" <td>2</td>\n",
" <td>0.246172</td>\n",
" <td>0.658124</td>\n",
" <td>0.000000</td>\n",
" <td>0.904296</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>0.372526</td>\n",
" <td>0.846183</td>\n",
" <td>0.000000</td>\n",
" <td>1.218709</td>\n",
" </tr>\n",
" <tr>\n",
" <td>20</td>\n",
" <td>0.463237</td>\n",
" <td>0.975418</td>\n",
" <td>0.000000</td>\n",
" <td>1.438655</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40</td>\n",
" <td>5.897614</td>\n",
" <td>1.306502</td>\n",
" <td>0.000000</td>\n",
" <td>7.204116</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>2</td>\n",
" <td>4.623390</td>\n",
" <td>0.823443</td>\n",
" <td>0.000000</td>\n",
" <td>5.446832</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">2,2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>20</td>\n",
" <td>40</td>\n",
" <td>1.464316</td>\n",
" <td>0.000000</td>\n",
" <td>2.380671</td>\n",
" <td>3.844987</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"4\" valign=\"top\">40</td>\n",
" <td>2</td>\n",
" <td>0.482502</td>\n",
" <td>0.000000</td>\n",
" <td>3.510194</td>\n",
" <td>3.992695</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>1.026574</td>\n",
" <td>0.000000</td>\n",
" <td>2.781301</td>\n",
" <td>3.807875</td>\n",
" </tr>\n",
" <tr>\n",
" <td>20</td>\n",
" <td>1.397894</td>\n",
" <td>0.000000</td>\n",
" <td>2.814464</td>\n",
" <td>4.212358</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40</td>\n",
" <td>1.445946</td>\n",
" <td>0.000000</td>\n",
" <td>1.597486</td>\n",
" <td>3.043431</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>160 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" TC TS TA TR\n",
"Dist %Async NP NS \n",
"1,1 0.0 2 2 0.246172 0.658124 0.000000 0.904296\n",
" 10 0.372526 0.846183 0.000000 1.218709\n",
" 20 0.463237 0.975418 0.000000 1.438655\n",
" 40 5.897614 1.306502 0.000000 7.204116\n",
" 10 2 4.623390 0.823443 0.000000 5.446832\n",
"... ... ... ... ...\n",
"2,2 100.0 20 40 1.464316 0.000000 2.380671 3.844987\n",
" 40 2 0.482502 0.000000 3.510194 3.992695\n",
" 10 1.026574 0.000000 2.781301 3.807875\n",
" 20 1.397894 0.000000 2.814464 4.212358\n",
" 40 1.445946 0.000000 1.597486 3.043431\n",
"\n",
"[160 rows x 4 columns]"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggM"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>N</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>N_par</th>\n",
" <th>NS</th>\n",
" <th>Dist</th>\n",
" <th>Compute_tam</th>\n",
" <th>Comm_tam</th>\n",
" <th>Time</th>\n",
" <th>Iters</th>\n",
" <th>Ti</th>\n",
" <th>Tt</th>\n",
" <th>To</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>0</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>10</td>\n",
" <td>0.009826</td>\n",
" <td>0.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>1</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>10</td>\n",
" <td>0.025812</td>\n",
" <td>0.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>2</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>10</td>\n",
" <td>0.009819</td>\n",
" <td>0.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>3</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>10</td>\n",
" <td>0.011071</td>\n",
" <td>0.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>4</td>\n",
" <td>2000000000</td>\n",
" <td>0.0</td>\n",
" <td>40</td>\n",
" <td>20</td>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>10</td>\n",
" <td>0.009815</td>\n",
" <td>0.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td>14951</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1</td>\n",
" <td>0.025818</td>\n",
" <td>1.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>14952</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1</td>\n",
" <td>0.009812</td>\n",
" <td>1.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>14953</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1</td>\n",
" <td>0.025813</td>\n",
" <td>1.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>14954</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1</td>\n",
" <td>0.025810</td>\n",
" <td>1.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>14955</td>\n",
" <td>2000000000</td>\n",
" <td>50.0</td>\n",
" <td>40</td>\n",
" <td>0</td>\n",
" <td>20</td>\n",
" <td>1</td>\n",
" <td>100000</td>\n",
" <td>0</td>\n",
" <td>0.2</td>\n",
" <td>1</td>\n",
" <td>0.009820</td>\n",
" <td>1.0</td>\n",
" <td>11.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>14956 rows × 13 columns</p>\n",
"</div>"
],
"text/plain": [
" N %Async NP N_par NS Dist Compute_tam Comm_tam Time \\\n",
"0 2000000000 0.0 40 20 0 2 100000 0 0.2 \n",
"1 2000000000 0.0 40 20 0 2 100000 0 0.2 \n",
"2 2000000000 0.0 40 20 0 2 100000 0 0.2 \n",
"3 2000000000 0.0 40 20 0 2 100000 0 0.2 \n",
"4 2000000000 0.0 40 20 0 2 100000 0 0.2 \n",
"... ... ... .. ... .. ... ... ... ... \n",
"14951 2000000000 50.0 40 0 20 1 100000 0 0.2 \n",
"14952 2000000000 50.0 40 0 20 1 100000 0 0.2 \n",
"14953 2000000000 50.0 40 0 20 1 100000 0 0.2 \n",
"14954 2000000000 50.0 40 0 20 1 100000 0 0.2 \n",
"14955 2000000000 50.0 40 0 20 1 100000 0 0.2 \n",
"\n",
" Iters Ti Tt To \n",
"0 10 0.009826 0.0 11.0 \n",
"1 10 0.025812 0.0 11.0 \n",
"2 10 0.009819 0.0 11.0 \n",
"3 10 0.011071 0.0 11.0 \n",
"4 10 0.009815 0.0 11.0 \n",
"... ... ... ... ... \n",
"14951 1 0.025818 1.0 11.0 \n",
"14952 1 0.009812 1.0 11.0 \n",
"14953 1 0.025813 1.0 11.0 \n",
"14954 1 0.025810 1.0 11.0 \n",
"14955 1 0.009820 1.0 11.0 \n",
"\n",
"[14956 rows x 13 columns]"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfL"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>Ti</th>\n",
" <th>Iters</th>\n",
" <th>To</th>\n",
" <th>Iters2</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Tt</th>\n",
" <th>Dist</th>\n",
" <th>%Async</th>\n",
" <th>NP</th>\n",
" <th>NS</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">1</td>\n",
" <td rowspan=\"5\" valign=\"top\">0.0</td>\n",
" <td rowspan=\"4\" valign=\"top\">2</td>\n",
" <td>2</td>\n",
" <td>0.199702</td>\n",
" <td>1.0</td>\n",
" <td>224.0</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>0.199709</td>\n",
" <td>1.0</td>\n",
" <td>224.0</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>20</td>\n",
" <td>0.199704</td>\n",
" <td>1.0</td>\n",
" <td>224.0</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40</td>\n",
" <td>0.199695</td>\n",
" <td>1.0</td>\n",
" <td>224.0</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>2</td>\n",
" <td>0.039240</td>\n",
" <td>1.0</td>\n",
" <td>44.0</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"5\" valign=\"top\">1.0</td>\n",
" <td rowspan=\"5\" valign=\"top\">2</td>\n",
" <td rowspan=\"5\" valign=\"top\">100.0</td>\n",
" <td>20</td>\n",
" <td>40</td>\n",
" <td>0.057025</td>\n",
" <td>21.0</td>\n",
" <td>22.0</td>\n",
" <td>21.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td rowspan=\"4\" valign=\"top\">40</td>\n",
" <td>2</td>\n",
" <td>0.021417</td>\n",
" <td>81.0</td>\n",
" <td>11.0</td>\n",
" <td>81.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>0.021047</td>\n",
" <td>66.0</td>\n",
" <td>11.0</td>\n",
" <td>66.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>20</td>\n",
" <td>0.024609</td>\n",
" <td>54.0</td>\n",
" <td>11.0</td>\n",
" <td>54.0</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40</td>\n",
" <td>0.030871</td>\n",
" <td>26.0</td>\n",
" <td>11.0</td>\n",
" <td>26.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>288 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" Ti Iters To Iters2\n",
"Tt Dist %Async NP NS \n",
"0.0 1 0.0 2 2 0.199702 1.0 224.0 1.0\n",
" 10 0.199709 1.0 224.0 1.0\n",
" 20 0.199704 1.0 224.0 1.0\n",
" 40 0.199695 1.0 224.0 1.0\n",
" 10 2 0.039240 1.0 44.0 1.0\n",
"... ... ... ... ...\n",
"1.0 2 100.0 20 40 0.057025 21.0 22.0 21.0\n",
" 40 2 0.021417 81.0 11.0 81.0\n",
" 10 0.021047 66.0 11.0 66.0\n",
" 20 0.024609 54.0 11.0 54.0\n",
" 40 0.030871 26.0 11.0 26.0\n",
"\n",
"[288 rows x 4 columns]"
]
},
"execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grouped_aggL"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO EJECUCCION\n",
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"EX numC= 2 p = 0.0 Diff = 0.675 Asíncrono\n",
"EX numC= 20 p = 0.012 Diff = 0.139 Síncrono\n",
"Para 10 padres\n",
"Para 20 padres\n",
"EX numC= 2 p = 0.0 Diff = 1.915 Asíncrono\n",
"EX numC= 20 p = 0.013 Diff = 0.705 Síncrono\n",
"EX numC= 40 p = 0.014 Diff = 0.8 Síncrono\n",
"Para 40 padres\n",
"EX numC= 20 p = 0.039 Diff = 0.734 Síncrono\n",
"EX numC= 40 p = 0.005 Diff = 0.368 Síncrono\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"EX numC= 2 p = 0.0 Diff = 0.691 Asíncrono\n",
"Para 10 padres\n",
"EX numC= 2 p = 0.0 Diff = 1.894 Asíncrono\n",
"Para 20 padres\n",
"EX numC= 10 p = 0.022 Diff = 0.513 Síncrono\n",
"EX numC= 40 p = 0.021 Diff = 0.434 Síncrono\n",
"Para 40 padres\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" if sys.path[0] == '':\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" del sys.path[0]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"EX numC= 20 p = 0.029 Diff = 0.762 Síncrono\n",
"EX numC= 40 p = 0.002 Diff = 0.302 Síncrono\n",
"SINC: 22 || ASINC: 10\n"
]
}
],
"source": [
"print(\"TIEMPO EJECUCCION\")\n",
"sinc = 0\n",
"asinc = 0\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" #if numP != numC:\n",
" group = str(numP) + \",\" + str(numC)\n",
" v1 = dfG[(dfG[\"%Async\"] == 0.0)][(dfG.Groups == group)][(dfG[\"Dist\"] == dist_v)]['TE']\n",
" v2 = dfG[(dfG[\"%Async\"] == 100.0)][(dfG.Groups == group)][(dfG[\"Dist\"] == dist_v)]['TE']\n",
" res = stats.ttest_ind(v1, v2)\n",
" diff = grouped_aggG['TE'].loc[(dist_v, 0.0, group)] - grouped_aggG['TE'].loc[(dist_v, 100.0, group)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" asinc+=1\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" sinc+=1\n",
" \n",
" if res[1] < p_value:\n",
" print(\"EX numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,3)), mejor)\n",
"print(\"SINC: \" + str(sinc) + \" || ASINC: \" + str(asinc))"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO MALLEABILITY\n",
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"TR numC= 2 p = 0.0 Diff = 0.143 Síncrono\n",
"Para 10 padres\n",
"TR numC= 10 p = 0.0 Diff = 0.05 Síncrono\n",
"TR numC= 20 p = 0.03 Diff = 0.087 Síncrono\n",
"Para 20 padres\n",
"TR numC= 10 p = 0.02 Diff = 0.531 Síncrono\n",
"TR numC= 20 p = 0.005 Diff = 0.839 Síncrono\n",
"TR numC= 40 p = 0.007 Diff = 0.877 Síncrono\n",
"Para 40 padres\n",
"TR numC= 2 p = 0.0 Diff = 2.23 Síncrono\n",
"TR numC= 10 p = 0.034 Diff = 0.791 Síncrono\n",
"TR numC= 20 p = 0.005 Diff = 1.086 Síncrono\n",
"TR numC= 40 p = 0.0 Diff = 0.453 Síncrono\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"TR numC= 2 p = 0.0 Diff = 0.13 Síncrono\n",
"Para 10 padres\n",
"TR numC= 2 p = 0.011 Diff = 0.116 Síncrono\n",
"TR numC= 10 p = 0.035 Diff = 0.929 Síncrono\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" if __name__ == '__main__':\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # Remove the CWD from sys.path while we load stuff.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"TR numC= 20 p = 0.02 Diff = 0.74 Síncrono\n",
"Para 20 padres\n",
"TR numC= 2 p = 0.008 Diff = 3.713 Síncrono\n",
"TR numC= 10 p = 0.001 Diff = 1.051 Síncrono\n",
"TR numC= 20 p = 0.028 Diff = 0.398 Síncrono\n",
"TR numC= 40 p = 0.037 Diff = 0.521 Síncrono\n",
"Para 40 padres\n",
"TR numC= 10 p = 0.04 Diff = 1.07 Síncrono\n",
"TR numC= 20 p = 0.001 Diff = 0.944 Síncrono\n",
"TR numC= 40 p = 0.001 Diff = 0.443 Síncrono\n"
]
}
],
"source": [
"print(\"TIEMPO MALLEABILITY\")\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" #if numP != numC:\n",
" v1 = dfM[(dfM[\"%Async\"] == 0.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM[\"Dist\"] == dist_v)]['TS']\n",
" v2 = dfM[(dfM[\"%Async\"] == 100.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM[\"Dist\"] == dist_v)]['TA']\n",
" res = stats.ttest_ind(v1, v2)\n",
" diff = grouped_aggM['TS'].loc[(dist_v, 0.0, numP, numC)] - grouped_aggM['TA'].loc[(dist_v, 100.0, numP, numC)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" if res[1] < p_value:\n",
" print(\"TR numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,3)), mejor)"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TIEMPO Iters\n",
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"Ti numC= 40 p = 0.02 Diff = 0.0421 Síncrono\n",
"Para 10 padres\n",
"Ti numC= 10 p = 0.012 Diff = 0.0 Síncrono\n",
"Ti numC= 20 p = 0.02 Diff = 0.0 Síncrono\n",
"Ti numC= 40 p = 0.0 Diff = 0.023 Síncrono\n",
"Para 20 padres\n",
"Ti numC= 2 p = 0.011 Diff = 0.0009 Síncrono\n",
"Ti numC= 10 p = 0.0 Diff = 0.0037 Síncrono\n",
"Ti numC= 20 p = 0.0 Diff = 0.0139 Síncrono\n",
"Ti numC= 40 p = 0.0 Diff = 0.0158 Síncrono\n",
"Para 40 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0089 Síncrono\n",
"Ti numC= 10 p = 0.0 Diff = 0.0099 Síncrono\n",
"Ti numC= 20 p = 0.0 Diff = 0.0125 Síncrono\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" if sys.path[0] == '':\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" del sys.path[0]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ti numC= 40 p = 0.0 Diff = 0.0208 Síncrono\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"Ti numC= 20 p = 0.048 Diff = 0.0463 Síncrono\n",
"Ti numC= 40 p = 0.003 Diff = 0.0688 Síncrono\n",
"Para 10 padres\n",
"Ti numC= 10 p = 0.0 Diff = 0.0218 Síncrono\n",
"Ti numC= 20 p = 0.0 Diff = 0.0373 Síncrono\n",
"Ti numC= 40 p = 0.0 Diff = 0.0409 Síncrono\n",
"Para 20 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0165 Síncrono\n",
"Ti numC= 10 p = 0.0 Diff = 0.0265 Síncrono\n",
"Ti numC= 20 p = 0.0 Diff = 0.041 Síncrono\n",
"Ti numC= 40 p = 0.0 Diff = 0.0374 Síncrono\n",
"Para 40 padres\n",
"Ti numC= 2 p = 0.0 Diff = 0.0116 Síncrono\n",
"Ti numC= 10 p = 0.0 Diff = 0.0112 Síncrono\n",
"Ti numC= 20 p = 0.0 Diff = 0.0148 Síncrono\n",
"Ti numC= 40 p = 0.0 Diff = 0.0211 Síncrono\n"
]
}
],
"source": [
"print(\"TIEMPO Iters\")\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" #if numP != numC:\n",
" #exp = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == 1)][(dfL[\"%Async\"] == 0.0)][(dfL.NP == numP)][(dfL.NS == numC)]\n",
" #TimeOp = exp['Ti'] \n",
" #print(TimeOp)\n",
" v1 = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']\n",
" v2 = dfL[(dfL[\"Tt\"] == 1)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']\n",
" res = stats.ttest_ind(v1, v2, equal_var = False)\n",
" diff = grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)] - grouped_aggL['Ti'].loc[(1, dist, 100.0, numP, numC)]\n",
" if diff > 0:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" if res[1] < p_value:\n",
" #and abs(diff) > grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)]\n",
" print(\"Ti numC=\", numC, \"p =\", round(res[1],3), \"Diff =\", abs(round(diff,4)), mejor)"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10.0\n"
]
}
],
"source": [
"auxIter = pd.DataFrame(dfM['Iters'].str.split(',',1).tolist(),columns = ['Iters0','Iters1'])\n",
"auxIter['Iters1'] = pd.to_numeric(auxIter['Iters1'], errors='coerce')\n",
"iters = auxIter['Iters1'].mean()\n",
"print(iters)\n"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Distribución BestFit -------------------------\n",
"Para 2 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 0.659\n",
"NC=10 Es mejor Asíncrono con una diff de 0.124\n",
"NC=20 Es mejor Asíncrono con una diff de 0.039\n",
"NC=40 Es mejor Síncrono con una diff de 0.077\n",
"Para 10 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.996\n",
"NC=10 Es mejor Asíncrono con una diff de 0.147\n",
"NC=20 Es mejor Asíncrono con una diff de 0.097\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" # Remove the CWD from sys.path while we load stuff.\n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" \n",
"/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n",
" app.launch_new_instance()\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"NC=40 Es mejor Síncrono con una diff de 0.16\n",
"Para 20 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.938\n",
"NC=10 Es mejor Síncrono con una diff de 0.137\n",
"NC=20 Es mejor Síncrono con una diff de 0.642\n",
"NC=40 Es mejor Síncrono con una diff de 0.775\n",
"Para 40 padres\n",
"NC=2 Es mejor Síncrono con una diff de 0.225\n",
"NC=10 Es mejor Síncrono con una diff de 0.397\n",
"NC=20 Es mejor Síncrono con una diff de 0.889\n",
"NC=40 Es mejor Síncrono con una diff de 0.351\n",
"Distribución WorstFit -------------------------\n",
"Para 2 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 0.671\n",
"NC=10 Es mejor Asíncrono con una diff de 0.132\n",
"NC=20 Es mejor Síncrono con una diff de 0.185\n",
"NC=40 Es mejor Síncrono con una diff de 0.455\n",
"Para 10 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.888\n",
"NC=10 Es mejor Síncrono con una diff de 0.536\n",
"NC=20 Es mejor Síncrono con una diff de 0.533\n",
"NC=40 Es mejor Síncrono con una diff de 0.176\n",
"Para 20 padres\n",
"NC=2 Es mejor Síncrono con una diff de 1.71\n",
"NC=10 Es mejor Síncrono con una diff de 0.657\n",
"NC=20 Es mejor Síncrono con una diff de 0.191\n",
"NC=40 Es mejor Síncrono con una diff de 0.416\n",
"Para 40 padres\n",
"NC=2 Es mejor Asíncrono con una diff de 1.02\n",
"NC=10 Es mejor Síncrono con una diff de 0.676\n",
"NC=20 Es mejor Síncrono con una diff de 0.738\n",
"NC=40 Es mejor Síncrono con una diff de 0.338\n"
]
}
],
"source": [
"#iters = dfM['Iters'].mean()\n",
"resultados = [0,0]\n",
"for dist in [1,2]:\n",
" print(\"Distribución \" + dist_names[dist] + \" -------------------------\")\n",
" dist_v = str(dist)+\",\"+str(dist)\n",
" for numP in values:\n",
" print(\"Para \", numP, \" padres\")\n",
" for numC in values:\n",
" #if numP != numC:\n",
" Titer = dfL[(dfL[\"Tt\"] == 0)][(dfL[\"Dist\"] == dist)][(dfL.NP == numC)]['Ti'].mean() #Tiempo por iteracion\n",
" i=0\n",
" for adr in [0.0, 100.0]:\n",
" \n",
" auxExp = dfM[(dfM[\"Dist\"] == dist_v)][(dfM[\"%Async\"] == adr)][(dfM.NP == numP)][(dfM.NS == numC)]\n",
" Tr = auxExp['TS'].mean() + auxExp['TA'].mean() #Tiempo de redistribucion\n",
" M_it = dfL[(dfL[\"Tt\"] == 1)][(dfL[\"Dist\"] == dist)][(dfL[\"%Async\"] == adr)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti'].count()/3 #Iteraciones asincronas\n",
" #No se presupone una diferencia temporal entre iteraciones sincronas y asincronas\n",
" if(M_it > iters):\n",
" M_it = iters\n",
" resultados[i] = (iters - M_it) * Titer + Tr\n",
" i+=1\n",
" #print(M_it)\n",
" #print(Titer)\n",
" #print(iters)\n",
" #print((iters - M_it) * Titer)\n",
" #print(Tr)\n",
" #print(\"End\")\n",
"\n",
" if resultados[0] > resultados[1]:\n",
" mejor = \"Asíncrono\"\n",
" else:\n",
" mejor = \"Síncrono\"\n",
" diff = abs(round(resultados[0] - resultados[1], 3))\n",
" print(\"NC=\"+ str(numC) + \" Es mejor \" + mejor + \" con una diff de \"+ str(diff))\n",
" #TODO Comprobar"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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QQqjBaBAKiIiIpIWKYnQa3wveo3vteFYeVk5i49cxczDw0RvWETp5FKF0namTWhFREREWtC4ZvSJM6LMODKyYU1peVl50KV1KwqkIiIiIjlkXsC0aHQqMmVefa9Q2n4USEVERESaae1qeoXS9qdAKiIiItJMxYyKVq+mbwylFTMqOriy7kkXNYmIiIg0k892oH0n99XFTe1EI6QiIiIiEigFUhEREREJlAKpiIiIiARKgVREREREAqVAKiIiIiKBUiAVERERkUApkIqIiIhIoBRIRURERCRQCqQiIiIiEigFUhEREREJlAKpiIiIiARKgVREREREAqVAKiIiIiKBUiAVERERkUApkIqIiIhIoBRIRURERCRQCqQiIiIiEigFUhEREREJlAKpiIiIiARKgVREREREAqVAKiIiIiKBUiAVERERkUApkIqIiIhIoBRIRURERCRQCqQiIiIiEigFUhEREREJlAKpiIiIiARKgVREREREAlXQQGpmh5rZR2Y2x8wuyfH8BWY2y8zeMbOnzWxwIesRERERkc6nYIHUzMLAdcBhwFjgBDMb2+y0N4GJ7r4rcC9wVaHqEREREZHOqZAjpHsCc9x9nrvXAHcBR2We4O5l7r4+/fAVYGAB6xERERGRTqiQgXQA8FnG44XpYy05DfhXrifM7Ewzm2lmM5ctW9aOJYqIiIhI0AoZSC3HMc95otmJwETgd7med/eb3X2iu0/s379/O5YoIiIiIkGLFPC1FwKDMh4PBBY1P8nMDgZ+Chzg7tUFrEdEREREOqFCjpDOAEaa2VAziwHHA9MzTzCzCcBNwJHuvrSAtYiIiIhIJ1WwQOrudcC5wOPAB8A0d3/fzC43syPTp/0O6AXcY2Zvmdn0Fl5ORERERLqpQk7Z4+6PAo82O3ZZxv2DC/n+IiIiItL5aacmEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiIBEqBVEREREQCpUAqIiIiIoFSIBURERGRQCmQioiIiEigFEhFREREJFAKpCIiIiISKAVSEREREQmUAqmIiIiI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\n",
"text/plain": [
"<Figure size 720x504 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAqQAAAHhCAYAAAC4O6zrAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXhU1f3H8fc3JKwJe0DZEgiEJAQRQbaya0VEXKDgjmu1WlrXqm2pS7WK/qRVbG1Fi4pbK+64UwkoKAqoyKIsIvsia9hDlvP748zAECbJBBImgc/reeYhM3PnzvfeWfjMueeca845RERERESiJSbaBYiIiIjI8U2BVERERESiSoFURERERKJKgVREREREoio22gWIiIiIVERz5sxpFBsb+zSQiRrxykIBMD8vL++aTp06/RR6hwKpiIiISBixsbFPn3DCCemJiYlbY2JiNC3RESooKLCNGzdmrF+//mngnND7lPZFREREwstMTEzcrjBaNmJiYlxiYmI2vsX54PuiUI+IiIhIZRBTYhgdNaoxkyYlFLvMpEkJjBrVuCwLq6wC+/OQ/KlAKiIiInK4unbdzYgRrYoMpZMmJTBiRCu6dt1d2lUvXbo0rmvXrqmtWrVq17p163b33XdfoyOuN4yhQ4cmP/PMM/XKY92RUiAVEREROVyDB+9gwoRlYUNpMIxOmLCMwYN3lHbVcXFxjBkzZvWyZcsWzJo167t///vfjebMmVO9zGovQV5e3tF6KgVSERERkSMSLpQeYRgFSEpKyu3Zs+dugHr16hWkpKTsWblyZdXCyw0dOjT54osvbtGpU6e2ycnJmS+//HIdgEWLFlXt1KlT24yMjPSMjIz0yZMn1wIoKChgxIgRLVJSUtr17du39aZNm/YPcm/atGn722677cROnTq1HT9+fL0FCxZU69WrV5t27dqld+rUqe3XX39dHWD8+PH12rRp065t27YZnTt3bns42xdKo+xFRERESnLVVc2ZP79mscs0bpzLkCFtSEzMZePGOFJS9nLffU24777wy2dm7mb8+FWRPP2iRYuqLly4sGafPn12hrt/1apV1b788stFCxcurHb66ae3Pffcc+c1adIk79NPP11cs2ZNN2/evGoXXXRRq/nz53/3/PPP1126dGm1RYsWLVi9enVc+/bt211xxRWbg+uqXr16wZw5cxYBdO/ePXXcuHEr2rdvnzNlypRa119/fYuZM2cuHj169IkfffTR4pYtW+Zu2rSpSiTbUBwFUhEREZGyULt2PomJuaxbV5UTT9xH7dr5ZbHa7OzsmCFDhqSMHj16Vf369QvCLTN06NAtVapUoX379jnNmzfP+eabb6q3bdt239VXX520cOHCGjExMaxYsaIawLRp0xKGDx++JTY2luTk5Nzu3bsf1II7YsSIrcHn/frrr+OHDRuWErxv3759BtC5c+edl1xySfLQoUO3XnLJJVuPdBsVSEVERERKEklLZvAw/Y03ruO55xL505/WHu7h+qCcnBwbNGhQyrBhw7Zcfvnl24pazswOuf6Xv/ylcaNGjXJfe+21HwsKCqhRo0anopYPlZCQUACQn59PQkJC3vfff7+w8DIvvfTSyilTptR6++2365x88sntvvnmmwUnnHDCYQdw9SEVEREROVKhfUYffXRtkQOdSqGgoIALL7wwKTU1de8999yzobhlX3/99Xr5+fksWLCg2qpVq6p16NBhb3Z2dpUTTzwxt0qVKjzxxBMN8vN9XuzTp8+OiRMn1s/Ly2PFihVxM2fODFtj/fr1C5o1a7Zv/Pjx9YL1fP755zUAFixYUK1///67Hn300bX16tXLW7Zs2SF9W0tDgVRERETkSIQbwFTc6PsITZ48Of7NN99sMH369IS0tLSMtLS0jP/+9791wi3bunXrnC5durQdNGhQm0cffXRFzZo13U033fTTyy+/3KBDhw5pixcvrl6jRo0CgMsuu2xbq1atctq2bdvu6quvbtGlS5ciW3FffvnlZc8880zDtm3bZrRp06bda6+9Vhfg5ptvbpaamprRpk2bdt26ddvRrVu3PYezjUHmnE4+ICIiIlLY3Llzl3fo0GFTsQuVNJq+DEbbl2To0KHJZ599dvaVV155xH05j4a5c+c27NChQ3LobWohFRERETlcX3xRs9iwGWwp/eKL4kfoH+fUQioiIiISRkQtpFJqaiEVERERkQpHgVREREREokqBVERERESiSoFURERE5HDNHdWYNSVM67RmUgJzRzU+ShVVSgqkIiIiIoerYdfdfDaiVZGhdM2kBD4b0YqGXXcfzuqHDRuWXL9+/Q5t2rRpF3r7hg0bqvTo0aNNUlJSZo8ePdps3LjxiM8nX9jYsWMbjBgxokVZrzccBVIRERGRw9V08A56TFgWNpQGw2iPCctoenhzkF511VWb3n777SWFb7/77rtP7Nu3744VK1bM79u374677rrrhMPcglLLzc0t83UqkIqIiIgciXChtAzCKMDAgQN3JiYm5hW+/YMPPqh73XXXbQa47rrrNr///vv1Ci8zduzYBqeddlpKr1692iQnJ2feeuutJwbvO/3001PatWuX3rp163aPPPJIw+Dtjz32WIPk5OTMU089te1nn30WH7x96NChyddcc02zrl27pt5www3Ntm/fHjNs2LDkzMzM9PT09IwXXnihLsDs2bOrt2/fPj0tLS0jNTU1Y968edUi2c7Y0u0WERERkePQzKuas21+8ZPbV2+cyydD2lAtMZecjXHEp+xl3n1NmHdf+OXrZu6m2/hVh1PO5s2bY5OSknIBkpKScrds2RI203377be15s2btyA+Pr6gY8eOGeeee2527969d7/44ovLGzdunL9z507r2LFjxqWXXro1JycnZvTo0U3mzJnzXf369fN79OjRNjMzc39Xgx9++KH6jBkzFsfGxjJy5Mim/fr12z5x4sTlmzZtqtK5c+f0c845Z/vjjz+eeMMNN2y4/vrrt+zdu9fy8g7J0mEpkIqIiIiUhbja+VRLzGXvuqpUP3EfcbXzo11Sz549t59wwgn5AIMGDdo6derU+N69e+9+6KGHGr/77rt1AdavXx+3YMGC6mvXro3r1q3bjiZNmuQBDBkyZMvixYurB9c1ZMiQrbGxPjpOnTq19ocfflh37NixJwDk5OTY0qVLq3bv3n3XI488cuLq1aurXnjhhVvbt2+fE0mdCqQiIiIiJYmkJTN4mL7tjetY9lwi7f+09kgO1xenQYMGeStWrIhLSkrKXbFiRVz9+vXDNkWa2SHX33nnnYRp06YlzJ49+/uEhISCLl26tN2zZ09MuOVDxcfHFwT/ds7x6quvLu3QocNBgfOUU07Z26tXr11vvPFGnYEDB6Y+8cQTy88555wS94H6kIqIiIgcqdA+o50eXVvkQKcyMmDAgG1PPvlkA4Ann3yywZlnnrkt3HLTp0+vvWHDhio7d+609957r26fPn12btu2rUqdOnXyExISCr7++uvqc+fOrQXQu3fvXTNnzkxYv359lZycHHvjjTcO6Zca1K9fv+1jxoxpXFDgM+qMGTNqACxc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OXLkxgEDBuxcsmRJ1QEDBrRZtmzZgv79+7e+8847151xxhm7srOzY2rWrFkQFxdXeL8ecqYmTYwvIiIiUgZia8fmxyXG5e5bt69q1ROr7isujEbi5ZdfrtOwYcO8Xr167X7nnXf2dwcI15ho/vTDhxg4cOC2+Ph4Fx8fn9e9e/ftn376aa3hw4dn33TTTc1mzpwZHxMTw08//VR19erVsVlZWfFnnXXWtoSEhAKAM844Y1voui666KItwb9nzJhRe8mSJfuPPuzcubPK1q1bY7p167bztttuaz58+PAtF1100daUlJQiT1gSqtwCqZmNxx8K+ck5d0i/NfPncb4jcHUncH3oYVQRERGRiqKklkw4cJi+6Y1N1214bkNi0p+S1h7J4frp06fHT548uW7Tpk3r5OTkxOzatSvm3HPPbfnGG2/8uGPHjiq5ubnExcWxfPnyqo0aNQrbsdPMDrn+5JNP1t+8eXPsvHnzvqtWrZpr2rRp+z179sSEWz5UMKiCD8WzZ8/+Lj4+/qAg/MADD6w/77zzst966606PXr0SP/ggw8Wd+zYcW9J21qefUifxfexKsqPQB/n3EnAffiJ2UVEREQqndA+o20ebbO2qIFOpfGPf/xjzYYNG75ds2bNvGeffXZZt27ddrz11ls/xsTE0K1btx3PPPNMPYDx48c3OPvss7eFW8f7779fd/fu3bZ+/foqM2fOTOjZs+eu7OzsKg0bNsytVq2amzRpUsLatWurAvTv33/nu+++W3fnzp22devWmMmTJxc5e0fPnj23P/TQQ/unWvzss89qACxYsKBaly5d9vzlL39Z3759+13z58+vHsm2llsgdc59gp/Psaj7PwuZN28mfnCDiIiISKUSbgBTcaPvy8KYMWNWP/744ye0aNEic+vWrbE33nhj2MF4HTt23HXaaae16dq1a/ptt922Ljk5Ofeaa67ZMnfu3FqZmZnpL7zwQv2WLVvuBejZs+fu888/f0tmZma7s88+O6VLly47i3r+cePGrfrqq69qpaamZqSkpLT7+9//ngjw8MMPN2rTpk27tm3bZtSoUaPgF7/4RXYk21Oug5rMnxninXCH7AstdxuQ5pw75LSPgfuvxZ8ekFq1anVKS0sr40oPtWzjLgBaJdYq9+eSsqHXTIqj94eIlNbDDz/MCSf4aX9z8vzR6mqxB7fl7ftiH9m3ZlNnTB2qdq16yDp2fborP+fOHHeko+0Pxy233NIkPj4+/89//vOGkpc+eirkoCYz64efJ7NnUcs4f07dcQCdO3d2s2fPLve6LnjSn376v9eFPbmGVEB6zaQ4en+ISGl99913pKenA/DDRt9YmJJ48MkIV76zkqTXkqjXr17YdcwvmJ/TckLL1du/2F7zaAfSyiSqgdTMTsLPATjQHXyuYREREZEKr8XtRZ7Qbb+GgxvuiEYY/etf/1rUmRArnKhNjB+Y+Pp14DLn3OJo1SEiIiIi0VWe0z69DPQFGprZavxp/+IAnHP/wp8ysgH+dHcAec65zuVVj4iIiEhpOeeKnQpJSqegoMDwp1c+SLkFUufcRSXcfw0QdhCTiIiISLRVr16dzZs306BBg2iXckwoKCiwjRs31uHgU+ACFWBQk4iIiEhF1KxZM1avXs3GjRvZuCMHgH2bqpXwqIOtX78+Nj8/v2F51FcJFQDz8/LyDmmQVCAVERERCSMuLo6WLVsCcM/+mTpOLtU6MjIy5qlLYsmiNqhJRERERAQUSEVEREQkyhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEhFREREJKoUSEVEREQkqhRIRURERCSqFEiDHn4YsrKKXyYryy8nIiIiImWm3AKpmY03s5/MbH4R95uZjTWzpWb2rZmdUl61ROTUU2H48KJDaVaWv//UU49uXSIiIiLHuPJsIX0WOLOY+wcCbQKX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fs/4rEvY6h7tMbWjIt2ZBc3bLKB/BCa1fW7d/jpqtta0uR3s7hd3U725muj+xCUD594O6441Vn/QGEal4yiQiki3Vl8zenzeLfRPm8JXTv9sj2poEhEIpgcJFgZJL0yiZGB34pKBFfdvYNRyx6DvDFIYTYGuv96CiMhBim9g6p82BWjaIVuyvsTnEYpIV2JmhHJDZI7JJO+kPPpf3J8hVw0h//R8snbBsrOClN1VRnlJeftvJgdEgVREuqW2uukVSkUkWfU1o09dGqb03BDjF41n9YLVCqUdTIFURLql0rLSNi/L14fS0rLSTh6ZiBwu4huYysZ4kSl/Tr5CaQqohlREuqVktgOdM0Lb/4lIYs276Vnb+Fx8KFWDU8fQDKmIiIhIMxWlFW2GzfpQWlFa0ckj6540QyoiIiLSTDLbgebPydfsaAfRDKmIiIiI+EqBVERERER8pUAqIiIiIr5SIBURERERXymQioiIiIivFEhFRERExFcKpCIiIiLiKwVSEREREfGVAqmIiIiI+EqBVERERER8pUAqIiIiIr5SIBURERERXymQioiIiIivFEhFRERExFcKpCIiIiLiKwVSEREREfGVAqmIiIiI+EqBVERERER8pUAqIiIiIr5SIBURERERXymQioiIiIivFEhFRERExFcKpCIiIiLiKwVSEREREfGVAqmIiIiI+EqBVERERER8pUAqIiIiIr5KaSA1s7lm9raZvWtm1yd4/mozW21mb5jZ02Y2LJXjEREREZGuJ2WB1MyCwK+BM4HxwKfMbHyz014FpjrnJgGLgdtSNR4RERER6ZpSOUM6HXjXOfeec64aKAbOiz/BOVfinKuM3X0ZGJLC8YiIiIhIF5TKQDoY+DDu/sbYY635EvC3RE+Y2WVmtszMlm3btq0DhygiIiIifktlILUEj7mEJ5p9BpgK/CTR8865e5xzU51zU/v169eBQxQRERERv4VS+N4bgaFx94cAZc1PMrNTgW8DJznnqlI4HhERERHpglI5Q1oKjDazEWYWAYqAJfEnmNkxwG+Ac51zW1M4FhERERHpolIWSJ1ztcDXgCeBNcAi59wqM7vZzM6NnfYToBfwoJm9ZmZLWnk7EREREemmUnnJHufcE8ATzR67Ke72qan8/iIiIiLS9WmnJhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIrxRIRURERMRXCqQiIiIi4isFUhERERHxlQKpiIiIiPhKgVREREREfKVAKiIiIiK+UiAVEREREV8pkIqIiIiIr1IaSM1srpm9bWbvmtn1CZ5PM7OFsedfMbPhqRyPiIiIiHQ9KQukZhYEfg2cCYwHPmVm45ud9iWg3Dk3CvgF8ONUjUdEREREuqZUzpBOB951zr3nnKsGioHzmp1zHvDH2O3FwClmZikck4iIiIh0MakMpIOBD+Pub4w9lvAc51wtsAvok8IxiYiIiEgXE0rheyea6XQHcQ5mdhlwWezuHjN7+xDHlqy+i77Cx530vaRj6M9M2qKfDxE5FAfzO2RYSkbSzaQykG4EhsbdHwKUtXLORjMLAbnAjuZv5Jy7B7gnReNslZktc85N7ezvKwdPf2bSFv18iMih0O+Q1EnlJftSYLSZjTCzCFAELGl2zhLg87Hb84FnnHMtZkhFREREpPtK2Qypc67WzL4GPAkEgd8751aZ2c3AMufcEuBe4H4zexdvZrQoVeMRERERka4plZfscc49ATzR7LGb4m7vBy5K5RgOUaeXCcgh05+ZtEU/HyJyKPQ7JEVMV8hFRERExE/aOlREREREfKVAmoCZDTWzEjNbY2arzOwqv8ckLZnZ781sq5mtjHust5n9w8zeiX3N93OM4p/W/h7rZ0REkmVmQTN71cwei90fEdvq/J3Y1ucRv8fYXSiQJlYLfNM5Nw44Drgiwban4r8/AHObPXY98LRzbjTwdOy+9Eyt/T3Wz4iIJOsqYE3c/R8Dv4j9/ijH2wJdOoACaQLOuU3OuRWx2xV4P4zNd5kSnznnnqflurXx29H+ETi/UwclXUYbf4/1MyIi7TKzIcDZwO9i9w34BN5W56DfHx1KgbQdZjYcOAZ4xd+RSJIKnHObwAskQH+fxyNdQLO/x/oZEZFk3A5cC0Rj9/sAO2NbnUPiLdHlICmQtsHMegEPAf/lnNvt93hE5MDp77GIHCgzOwfY6pxbHv9wglO1VFEHSek6pIczMwvj/SP2gHPuYb/HI0nbYmYDnXObzGwgsNXvAYl/Wvl7rJ8REWnPTOBcMzsLSAdy8GZM88wsFJslTbQluhwkzZAmEKsTuRdY45z7ud/jkQMSvx3t54FHfByL+KiNv8f6GRGRNjnnbnDODXHODcfbRfIZ59yngRK8rc5Bvz86lBbGT8DMZgFLgTdprB25MbbzlHQRZvZn4GSgL7AF+C7wV2ARUAhsAC5yzjVvfJIeoLW/x3h1pPoZEZGkmNnJwLecc+eY2RFAMdAbeBX4jHOuys/xdRcKpCIiIiLiK12yFxERERFfKZCKiIiIiK8USEVERETEVwqkIiIiIuIrBVIRERER8ZUCqYh0CWZWZ2avmdlKM3vQzDL9HlOyzOxZM5ua4PGpZvbL2O1zzez6zh+diEjXp2WfRKRLMLM9zrlesdsPAMvjF7SPLXRvzrloa+/hFzN7Fm+dwmV+j0VE5HCkGVIR6YqWAqPMbLiZrTGzO4EVwFAz+5SZvRmbSf1x/QvMbK6ZrTCz183s6dhjWWb2ezMrNbNXzey82OMTzOzfsRnZN8xsdOzxq2Pvu9LM/ivuPR6Pve9KM7u4lTFfFHvPtWY2O/bak83ssdjtL5jZr2K3h5nZ07Hv/bSZFabmP6OIyOFBe9mLSJdiZiHgTODvsYfGAJc4575qZoOAHwNTgHLgKTM7H3gR+C1wonNuvZn1jr3223hb/n3RzPKAf5vZP4GvAHc45x4wswgQNLMpwCXADMCAV8zsOeAIoMw5d3ZsfLmtDD3knJse2/v6u8CpbXzMXwH3Oef+aGZfBH4JnH9g/6VERLoPzZCKSFeRYWavAcvwtvS8N/b4B865l2O3pwHPOue2OedqgQeAE4HjgOedc+sB4rYCPR24Pva+zwLpeFuGvgTcaGbXAcOcc/uAWcBfnHN7nXN7gIeB2Xhbj55qZj82s9nOuV2tjP/h2NflwPB2PuvxwJ9it++PfW8RkR5LM6Qi0lXsc84dHf+AVzbK3viHWnmtAYkK4g240Dn3drPH15jZK8DZwJNm9p+tvbdzbm1s9vQs4H/M7Cnn3M0JTq3fz7qOA//dqmJ+EenRNEMqIoeTV4CTzKyvmQWBTwHP4c14nmRmIwDiLtk/CVwZa4jCzI6JfT0CeM8590tgCTAJeB4438wyzSwLuABYGisTqHTO/R/wU+DYDvgc/wKKYrc/DbzQAe8pInLY0gypiBw2nHObzOwGoARvRvMJ59wjAGZ2GfCwmQWArcBpwC3A7cAbsVD6PnAOcDHwGTOrATYDNzvndpjZH4B/x77d75xzr5rZGcBPzCwK1ACXH8pHiH39OvB7M7sG2IZXuyoi0mNp2ScRkU5gZt8Ecpxz3/V7LCIiXY1mSEVEUszMvgJ8Afikz0MREemSNEMqIiIiIr5SU5OIiIiI+EqBVERERER8pUAqIiIiIr5SIBURERERXymQioiIiIivFEhFRERExFf/H9/4Pss2XlfLAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 720x504 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"for dist in [1,2]:\n",
" v1 = grouped_aggL.loc[(0,dist,100.0,slice(None))]\n",
" v2 = grouped_aggL.loc[(1,dist,100.0,slice(None))]\n",
" aux_aggL = v1['Ti'].values / v2['Ti'].values\n",
"\n",
" colors = ['r', 'orange', 'g', 'm', 'y']\n",
" markers = ['+', 'x', '1', '2', 'X']\n",
"\n",
" f=plt.figure(figsize=(10, 7))\n",
" ax1 = f.add_subplot(111)\n",
" plt.xlim(0, max(values)+1)\n",
" plt.ylim(0, 1.2)\n",
" plt.xticks(values)\n",
" ax1.set_ylabel('Aumento de velocidad')\n",
" ax1.set_xlabel('Procesos hijo')\n",
" ax1.set_title(\"Aumento de velocidad al realizar redistribuciones asíncronas - \" + dist_names[dist])\n",
"\n",
"\n",
" for i in range(len(values)):\n",
" numP = values[i]\n",
" c = colors[i]\n",
" \n",
" mini = i * len(values)\n",
" maxi = (i+1) * len(values)\n",
" array_values = aux_aggL[mini:maxi]\n",
" indexes = np.arange(len(values))\n",
" aux_j=0\n",
" for j in range(len(values)):\n",
" indexes[aux_j] = values[j]\n",
" aux_j+=1\n",
" \n",
" x = indexes\n",
" y = array_values\n",
" label = str(numP) + ' padres'\n",
" ax1.axvline(numP)\n",
" plt.plot(x, y, color=colors[i], label=label, marker=markers[1], markersize=10)\n",
" \n",
" ax1.axhline(1, color='k')\n",
" f.legend()\n",
" #f.tight_layout()\n",
" f.savefig(\"Images/\"+\"Iters\"+ dist_names[dist] +\"_SpeedUp\", format=\"png\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"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.7.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
%% Cell type:code id: tags:
``` python
%matplotlib inline
import pandas as pd
from pandas import DataFrame, Series
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
import sys
```
%% Cell type:code id: tags:
``` python
matrixMalEX="data_GG.csv"
matrixMal="data_GM.csv"
matrixIt="data_L.csv"
n_qty=2 #CAMBIAR SEGUN LA CANTIDAD DE NODOS USADOS
repet = 3 * 2 #CAMBIAR EL PRIMER NUMERO SEGUN NUMERO DE EJECUCIONES POR CONFIG
p_value = 0.05
values = [2, 10, 20, 40]
dist_names = ['null', 'BestFit', 'WorstFit']
```
%% Cell type:code id: tags:
``` python
def speedUp(arr, seq, df):
numP = df.loc[arr.index[0]].NP
return seq[( seq.NP == numP )]['EX'] / arr.mean()
```
%% Cell type:code id: tags:
``` python
dfG = pd.read_csv( matrixMalEX )
dfG = dfG.drop(columns=dfG.columns[0])
dfG['S'] = dfG['N']
dfG['N'] = dfG['S'] + dfG['%Async']
dfG['%Async'] = (dfG['%Async'] / dfG['N']) * 100
if(n_qty == 1):
group = dfG.groupby(['%Async', 'Groups'])['TE']
else:
group = dfG.groupby(['Dist', '%Async', 'Groups'])['TE']
#group
grouped_aggG = group.agg(['mean'])
grouped_aggG.rename(columns={'mean':'TE',}, inplace=True)
```
%% Cell type:code id: tags:
``` python
dfM = pd.read_csv( matrixMal )
dfM = dfM.drop(columns=dfM.columns[0])
dfM['S'] = dfM['N']
dfM['N'] = dfM['S'] + dfM['%Async']
dfM["TR"] = dfM["TC"] + dfM["TS"] + dfM["TA"]
dfM['%Async'] = (dfM['%Async'] / dfM['N']) * 100
if(n_qty == 1):
groupM = dfM.groupby(['%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']
else:
groupM = dfM.groupby(['Dist', '%Async','NP', 'NS'])['TC', 'TS', 'TA', 'TR']
#group
grouped_aggM = groupM.agg(['mean'])
grouped_aggM.columns = grouped_aggM.columns.get_level_values(0)
```
%% Cell type:code id: tags:
``` python
dfL = pd.read_csv( matrixIt )
dfL = dfL.drop(columns=dfL.columns[0])
if(n_qty == 1):
groupL = dfL[dfL['NS'] != 0].groupby(['Tt', '%Async', 'NP', 'NS'])['Ti', 'To']
else:
groupL = dfL[dfL['NS'] != 0].groupby(['Tt', 'Dist', '%Async', 'NP', 'NS'])['Ti', 'To']
#group
grouped_aggL = groupL.agg(['mean', 'count'])
grouped_aggL.columns = grouped_aggL.columns.get_level_values(0)
grouped_aggL.set_axis(['Ti', 'Iters', 'To', 'Iters2'], axis='columns')
grouped_aggL['Iters'] = np.ceil(grouped_aggL['Iters']/6) # TODO Cambiar a repeticiones realizadas
grouped_aggL['Iters2'] = np.ceil(grouped_aggL['Iters2']/6)
```
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: FutureWarning: set_axis currently defaults to operating inplace.
This will change in a future version of pandas, use inplace=True to avoid this warning.
if sys.path[0] == '':
%% Cell type:code id: tags:
``` python
grouped_aggL.to_excel("resultL.xlsx")
grouped_aggM.to_excel("resultM.xlsx")
grouped_aggG.to_excel("resultG.xlsx")
```
%% Cell type:code id: tags:
``` python
dfG
```
%%%% Output: execute_result
N %Async Groups Dist Matrix CommTam Time Iters TE \
0 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.325915
1 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.661673
2 2000000000 0.0 20,40 2,2 100000 0 0.2 1,10 3.647241
3 2000000000 75.0 10,40 1,1 100000 0 0.2 1,10 2.710496
4 2000000000 75.0 10,40 1,1 100000 0 0.2 1,10 2.785736
.. ... ... ... ... ... ... ... ... ...
475 2000000000 50.0 10,10 2,2 100000 0 0.2 1,10 1.292079
476 2000000000 50.0 10,10 2,2 100000 0 0.2 1,10 1.683571
477 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.107688
478 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.169551
479 2000000000 50.0 40,20 1,1 100000 0 0.2 1,10 3.442101
S
0 2000000000
1 2000000000
2 2000000000
3 500000000
4 500000000
.. ...
475 1000000000
476 1000000000
477 1000000000
478 1000000000
479 1000000000
[480 rows x 10 columns]
%% Cell type:code id: tags:
``` python
grouped_aggG
```
%%%% Output: execute_result
TE
Dist %Async Groups
1,1 0.0 10,10 7.238413
10,2 7.495134
10,20 1.052943
10,40 2.412291
2,10 1.812608
... ...
2,2 100.0 20,40 3.978562
40,10 3.869905
40,2 4.056287
40,20 4.384910
40,40 3.143114
[160 rows x 1 columns]
%% Cell type:code id: tags:
``` python
dfM
```
%%%% Output: execute_result
N %Async NP NS Dist Matrix CommTam Time Iters TC \
0 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.523284
1 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.395780
2 2000000000 0.0 20 40 2,2 100000 0 0.2 1,10 1.515433
3 2000000000 75.0 10 40 1,1 100000 0 0.2 1,10 1.331821
4 2000000000 75.0 10 40 1,1 100000 0 0.2 1,10 1.338515
.. ... ... .. .. ... ... ... ... ... ...
475 2000000000 50.0 10 10 2,2 100000 0 0.2 1,10 0.573135
476 2000000000 50.0 10 10 2,2 100000 0 0.2 1,10 0.568495
477 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.171373
478 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.227744
479 2000000000 50.0 40 20 1,1 100000 0 0.2 1,10 1.101387
TS TA S TR
0 1.571982 0.000000 2000000000 3.095266
1 2.067917 0.000000 2000000000 3.463697
2 1.939858 0.000000 2000000000 3.455291
3 0.217988 1.279915 500000000 2.829724
4 0.268872 1.359864 500000000 2.967251
.. ... ... ... ...
475 0.091322 0.679278 1000000000 1.343735
476 0.096622 1.075340 1000000000 1.740457
477 0.557700 1.843437 1000000000 3.572510
478 0.634888 1.881406 1000000000 3.744038
479 0.695218 2.296932 1000000000 4.093537
[480 rows x 14 columns]
%% Cell type:code id: tags:
``` python
grouped_aggM
```
%%%% Output: execute_result
TC TS TA TR
Dist %Async NP NS
1,1 0.0 2 2 0.246172 0.658124 0.000000 0.904296
10 0.372526 0.846183 0.000000 1.218709
20 0.463237 0.975418 0.000000 1.438655
40 5.897614 1.306502 0.000000 7.204116
10 2 4.623390 0.823443 0.000000 5.446832
... ... ... ... ...
2,2 100.0 20 40 1.464316 0.000000 2.380671 3.844987
40 2 0.482502 0.000000 3.510194 3.992695
10 1.026574 0.000000 2.781301 3.807875
20 1.397894 0.000000 2.814464 4.212358
40 1.445946 0.000000 1.597486 3.043431
[160 rows x 4 columns]
%% Cell type:code id: tags:
``` python
dfL
```
%%%% Output: execute_result
N %Async NP N_par NS Dist Compute_tam Comm_tam Time \
0 2000000000 0.0 40 20 0 2 100000 0 0.2
1 2000000000 0.0 40 20 0 2 100000 0 0.2
2 2000000000 0.0 40 20 0 2 100000 0 0.2
3 2000000000 0.0 40 20 0 2 100000 0 0.2
4 2000000000 0.0 40 20 0 2 100000 0 0.2
... ... ... .. ... .. ... ... ... ...
14951 2000000000 50.0 40 0 20 1 100000 0 0.2
14952 2000000000 50.0 40 0 20 1 100000 0 0.2
14953 2000000000 50.0 40 0 20 1 100000 0 0.2
14954 2000000000 50.0 40 0 20 1 100000 0 0.2
14955 2000000000 50.0 40 0 20 1 100000 0 0.2
Iters Ti Tt To
0 10 0.009826 0.0 11.0
1 10 0.025812 0.0 11.0
2 10 0.009819 0.0 11.0
3 10 0.011071 0.0 11.0
4 10 0.009815 0.0 11.0
... ... ... ... ...
14951 1 0.025818 1.0 11.0
14952 1 0.009812 1.0 11.0
14953 1 0.025813 1.0 11.0
14954 1 0.025810 1.0 11.0
14955 1 0.009820 1.0 11.0
[14956 rows x 13 columns]
%% Cell type:code id: tags:
``` python
grouped_aggL
```
%%%% Output: execute_result
Ti Iters To Iters2
Tt Dist %Async NP NS
0.0 1 0.0 2 2 0.199702 1.0 224.0 1.0
10 0.199709 1.0 224.0 1.0
20 0.199704 1.0 224.0 1.0
40 0.199695 1.0 224.0 1.0
10 2 0.039240 1.0 44.0 1.0
... ... ... ... ...
1.0 2 100.0 20 40 0.057025 21.0 22.0 21.0
40 2 0.021417 81.0 11.0 81.0
10 0.021047 66.0 11.0 66.0
20 0.024609 54.0 11.0 54.0
40 0.030871 26.0 11.0 26.0
[288 rows x 4 columns]
%% Cell type:code id: tags:
``` python
print("TIEMPO EJECUCCION")
sinc = 0
asinc = 0
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
#if numP != numC:
group = str(numP) + "," + str(numC)
v1 = dfG[(dfG["%Async"] == 0.0)][(dfG.Groups == group)][(dfG["Dist"] == dist_v)]['TE']
v2 = dfG[(dfG["%Async"] == 100.0)][(dfG.Groups == group)][(dfG["Dist"] == dist_v)]['TE']
res = stats.ttest_ind(v1, v2)
diff = grouped_aggG['TE'].loc[(dist_v, 0.0, group)] - grouped_aggG['TE'].loc[(dist_v, 100.0, group)]
if diff > 0:
mejor = "Asíncrono"
asinc+=1
else:
mejor = "Síncrono"
sinc+=1
if res[1] < p_value:
print("EX numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,3)), mejor)
print("SINC: " + str(sinc) + " || ASINC: " + str(asinc))
```
%%%% Output: stream
TIEMPO EJECUCCION
Distribución BestFit -------------------------
Para 2 padres
EX numC= 2 p = 0.0 Diff = 0.675 Asíncrono
EX numC= 20 p = 0.012 Diff = 0.139 Síncrono
Para 10 padres
Para 20 padres
EX numC= 2 p = 0.0 Diff = 1.915 Asíncrono
EX numC= 20 p = 0.013 Diff = 0.705 Síncrono
EX numC= 40 p = 0.014 Diff = 0.8 Síncrono
Para 40 padres
EX numC= 20 p = 0.039 Diff = 0.734 Síncrono
EX numC= 40 p = 0.005 Diff = 0.368 Síncrono
Distribución WorstFit -------------------------
Para 2 padres
EX numC= 2 p = 0.0 Diff = 0.691 Asíncrono
Para 10 padres
EX numC= 2 p = 0.0 Diff = 1.894 Asíncrono
Para 20 padres
EX numC= 10 p = 0.022 Diff = 0.513 Síncrono
EX numC= 40 p = 0.021 Diff = 0.434 Síncrono
Para 40 padres
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
if sys.path[0] == '':
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
del sys.path[0]
%%%% Output: stream
EX numC= 20 p = 0.029 Diff = 0.762 Síncrono
EX numC= 40 p = 0.002 Diff = 0.302 Síncrono
SINC: 22 || ASINC: 10
%% Cell type:code id: tags:
``` python
print("TIEMPO MALLEABILITY")
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
#if numP != numC:
v1 = dfM[(dfM["%Async"] == 0.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM["Dist"] == dist_v)]['TS']
v2 = dfM[(dfM["%Async"] == 100.0)][(dfM.NP == numP)][(dfM.NS == numC)][(dfM["Dist"] == dist_v)]['TA']
res = stats.ttest_ind(v1, v2)
diff = grouped_aggM['TS'].loc[(dist_v, 0.0, numP, numC)] - grouped_aggM['TA'].loc[(dist_v, 100.0, numP, numC)]
if diff > 0:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
if res[1] < p_value:
print("TR numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,3)), mejor)
```
%%%% Output: stream
TIEMPO MALLEABILITY
Distribución BestFit -------------------------
Para 2 padres
TR numC= 2 p = 0.0 Diff = 0.143 Síncrono
Para 10 padres
TR numC= 10 p = 0.0 Diff = 0.05 Síncrono
TR numC= 20 p = 0.03 Diff = 0.087 Síncrono
Para 20 padres
TR numC= 10 p = 0.02 Diff = 0.531 Síncrono
TR numC= 20 p = 0.005 Diff = 0.839 Síncrono
TR numC= 40 p = 0.007 Diff = 0.877 Síncrono
Para 40 padres
TR numC= 2 p = 0.0 Diff = 2.23 Síncrono
TR numC= 10 p = 0.034 Diff = 0.791 Síncrono
TR numC= 20 p = 0.005 Diff = 1.086 Síncrono
TR numC= 40 p = 0.0 Diff = 0.453 Síncrono
Distribución WorstFit -------------------------
Para 2 padres
TR numC= 2 p = 0.0 Diff = 0.13 Síncrono
Para 10 padres
TR numC= 2 p = 0.011 Diff = 0.116 Síncrono
TR numC= 10 p = 0.035 Diff = 0.929 Síncrono
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
if __name__ == '__main__':
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# Remove the CWD from sys.path while we load stuff.
%%%% Output: stream
TR numC= 20 p = 0.02 Diff = 0.74 Síncrono
Para 20 padres
TR numC= 2 p = 0.008 Diff = 3.713 Síncrono
TR numC= 10 p = 0.001 Diff = 1.051 Síncrono
TR numC= 20 p = 0.028 Diff = 0.398 Síncrono
TR numC= 40 p = 0.037 Diff = 0.521 Síncrono
Para 40 padres
TR numC= 10 p = 0.04 Diff = 1.07 Síncrono
TR numC= 20 p = 0.001 Diff = 0.944 Síncrono
TR numC= 40 p = 0.001 Diff = 0.443 Síncrono
%% Cell type:code id: tags:
``` python
print("TIEMPO Iters")
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
#if numP != numC:
#exp = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == 1)][(dfL["%Async"] == 0.0)][(dfL.NP == numP)][(dfL.NS == numC)]
#TimeOp = exp['Ti']
#print(TimeOp)
v1 = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == dist)][(dfL["%Async"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']
v2 = dfL[(dfL["Tt"] == 1)][(dfL["Dist"] == dist)][(dfL["%Async"] == 100.0)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti']
res = stats.ttest_ind(v1, v2, equal_var = False)
diff = grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)] - grouped_aggL['Ti'].loc[(1, dist, 100.0, numP, numC)]
if diff > 0:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
if res[1] < p_value:
#and abs(diff) > grouped_aggL['Ti'].loc[(0, dist, 0.0, numP, numC)]
print("Ti numC=", numC, "p =", round(res[1],3), "Diff =", abs(round(diff,4)), mejor)
```
%%%% Output: stream
TIEMPO Iters
Distribución BestFit -------------------------
Para 2 padres
Ti numC= 40 p = 0.02 Diff = 0.0421 Síncrono
Para 10 padres
Ti numC= 10 p = 0.012 Diff = 0.0 Síncrono
Ti numC= 20 p = 0.02 Diff = 0.0 Síncrono
Ti numC= 40 p = 0.0 Diff = 0.023 Síncrono
Para 20 padres
Ti numC= 2 p = 0.011 Diff = 0.0009 Síncrono
Ti numC= 10 p = 0.0 Diff = 0.0037 Síncrono
Ti numC= 20 p = 0.0 Diff = 0.0139 Síncrono
Ti numC= 40 p = 0.0 Diff = 0.0158 Síncrono
Para 40 padres
Ti numC= 2 p = 0.0 Diff = 0.0089 Síncrono
Ti numC= 10 p = 0.0 Diff = 0.0099 Síncrono
Ti numC= 20 p = 0.0 Diff = 0.0125 Síncrono
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
if sys.path[0] == '':
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
del sys.path[0]
%%%% Output: stream
Ti numC= 40 p = 0.0 Diff = 0.0208 Síncrono
Distribución WorstFit -------------------------
Para 2 padres
Ti numC= 20 p = 0.048 Diff = 0.0463 Síncrono
Ti numC= 40 p = 0.003 Diff = 0.0688 Síncrono
Para 10 padres
Ti numC= 10 p = 0.0 Diff = 0.0218 Síncrono
Ti numC= 20 p = 0.0 Diff = 0.0373 Síncrono
Ti numC= 40 p = 0.0 Diff = 0.0409 Síncrono
Para 20 padres
Ti numC= 2 p = 0.0 Diff = 0.0165 Síncrono
Ti numC= 10 p = 0.0 Diff = 0.0265 Síncrono
Ti numC= 20 p = 0.0 Diff = 0.041 Síncrono
Ti numC= 40 p = 0.0 Diff = 0.0374 Síncrono
Para 40 padres
Ti numC= 2 p = 0.0 Diff = 0.0116 Síncrono
Ti numC= 10 p = 0.0 Diff = 0.0112 Síncrono
Ti numC= 20 p = 0.0 Diff = 0.0148 Síncrono
Ti numC= 40 p = 0.0 Diff = 0.0211 Síncrono
%% Cell type:code id: tags:
``` python
auxIter = pd.DataFrame(dfM['Iters'].str.split(',',1).tolist(),columns = ['Iters0','Iters1'])
auxIter['Iters1'] = pd.to_numeric(auxIter['Iters1'], errors='coerce')
iters = auxIter['Iters1'].mean()
print(iters)
```
%%%% Output: stream
10.0
%% Cell type:code id: tags:
``` python
#iters = dfM['Iters'].mean()
resultados = [0,0]
for dist in [1,2]:
print("Distribución " + dist_names[dist] + " -------------------------")
dist_v = str(dist)+","+str(dist)
for numP in values:
print("Para ", numP, " padres")
for numC in values:
#if numP != numC:
Titer = dfL[(dfL["Tt"] == 0)][(dfL["Dist"] == dist)][(dfL.NP == numC)]['Ti'].mean() #Tiempo por iteracion
i=0
for adr in [0.0, 100.0]:
auxExp = dfM[(dfM["Dist"] == dist_v)][(dfM["%Async"] == adr)][(dfM.NP == numP)][(dfM.NS == numC)]
Tr = auxExp['TS'].mean() + auxExp['TA'].mean() #Tiempo de redistribucion
M_it = dfL[(dfL["Tt"] == 1)][(dfL["Dist"] == dist)][(dfL["%Async"] == adr)][(dfL.NP == numP)][(dfL.NS == numC)]['Ti'].count()/3 #Iteraciones asincronas
#No se presupone una diferencia temporal entre iteraciones sincronas y asincronas
if(M_it > iters):
M_it = iters
resultados[i] = (iters - M_it) * Titer + Tr
i+=1
#print(M_it)
#print(Titer)
#print(iters)
#print((iters - M_it) * Titer)
#print(Tr)
#print("End")
if resultados[0] > resultados[1]:
mejor = "Asíncrono"
else:
mejor = "Síncrono"
diff = abs(round(resultados[0] - resultados[1], 3))
print("NC="+ str(numC) + " Es mejor " + mejor + " con una diff de "+ str(diff))
#TODO Comprobar
```
%%%% Output: stream
Distribución BestFit -------------------------
Para 2 padres
NC=2 Es mejor Asíncrono con una diff de 0.659
NC=10 Es mejor Asíncrono con una diff de 0.124
NC=20 Es mejor Asíncrono con una diff de 0.039
NC=40 Es mejor Síncrono con una diff de 0.077
Para 10 padres
NC=2 Es mejor Asíncrono con una diff de 1.996
NC=10 Es mejor Asíncrono con una diff de 0.147
NC=20 Es mejor Asíncrono con una diff de 0.097
%%%% Output: stream
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
# Remove the CWD from sys.path while we load stuff.
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
/home/usuario/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.
app.launch_new_instance()
%%%% Output: stream
NC=40 Es mejor Síncrono con una diff de 0.16
Para 20 padres
NC=2 Es mejor Asíncrono con una diff de 1.938
NC=10 Es mejor Síncrono con una diff de 0.137
NC=20 Es mejor Síncrono con una diff de 0.642
NC=40 Es mejor Síncrono con una diff de 0.775
Para 40 padres
NC=2 Es mejor Síncrono con una diff de 0.225
NC=10 Es mejor Síncrono con una diff de 0.397
NC=20 Es mejor Síncrono con una diff de 0.889
NC=40 Es mejor Síncrono con una diff de 0.351
Distribución WorstFit -------------------------
Para 2 padres
NC=2 Es mejor Asíncrono con una diff de 0.671
NC=10 Es mejor Asíncrono con una diff de 0.132
NC=20 Es mejor Síncrono con una diff de 0.185
NC=40 Es mejor Síncrono con una diff de 0.455
Para 10 padres
NC=2 Es mejor Asíncrono con una diff de 1.888
NC=10 Es mejor Síncrono con una diff de 0.536
NC=20 Es mejor Síncrono con una diff de 0.533
NC=40 Es mejor Síncrono con una diff de 0.176
Para 20 padres
NC=2 Es mejor Síncrono con una diff de 1.71
NC=10 Es mejor Síncrono con una diff de 0.657
NC=20 Es mejor Síncrono con una diff de 0.191
NC=40 Es mejor Síncrono con una diff de 0.416
Para 40 padres
NC=2 Es mejor Asíncrono con una diff de 1.02
NC=10 Es mejor Síncrono con una diff de 0.676
NC=20 Es mejor Síncrono con una diff de 0.738
NC=40 Es mejor Síncrono con una diff de 0.338
%% Cell type:code id: tags:
``` python
for dist in [1,2]:
v1 = grouped_aggL.loc[(0,dist,100.0,slice(None))]
v2 = grouped_aggL.loc[(1,dist,100.0,slice(None))]
aux_aggL = v1['Ti'].values / v2['Ti'].values
colors = ['r', 'orange', 'g', 'm', 'y']
markers = ['+', 'x', '1', '2', 'X']
f=plt.figure(figsize=(10, 7))
ax1 = f.add_subplot(111)
plt.xlim(0, max(values)+1)
plt.ylim(0, 1.2)
plt.xticks(values)
ax1.set_ylabel('Aumento de velocidad')
ax1.set_xlabel('Procesos hijo')
ax1.set_title("Aumento de velocidad al realizar redistribuciones asíncronas - " + dist_names[dist])
for i in range(len(values)):
numP = values[i]
c = colors[i]
mini = i * len(values)
maxi = (i+1) * len(values)
array_values = aux_aggL[mini:maxi]
indexes = np.arange(len(values))
aux_j=0
for j in range(len(values)):
indexes[aux_j] = values[j]
aux_j+=1
x = indexes
y = array_values
label = str(numP) + ' padres'
ax1.axvline(numP)
plt.plot(x, y, color=colors[i], label=label, marker=markers[1], markersize=10)
ax1.axhline(1, color='k')
f.legend()
#f.tight_layout()
f.savefig("Images/"+"Iters"+ dist_names[dist] +"_SpeedUp", format="png")
```
%%%% Output: display_data
[Hidden Image Output]
%%%% Output: display_data
[Hidden Image Output]
%% Cell type:code id: tags:
``` python
```
import sys
import glob
import numpy as np
import pandas as pd
#-----------------------------------------------
def read_file(f, data, it):
compute_tam = 0
comm_tam = 0
sdr = 0
adr = 0
dist = 0
time = 0
recording = False
it_line = 0
aux_it = 0
iters = 0
np = 0
np_par = 0
ns = 0
columnas = ['Titer','Ttype','Top']
#print(f)
for line in f:
lineS = line.split()
if len(lineS) > 1:
if recording and lineS[0].split(':')[0] in columnas: #Record data
aux_it = 0
lineS.pop(0)
if it_line==0:
for observation in lineS:
data.append([None]*13)
data[it+aux_it][0] = sdr
data[it+aux_it][1] = adr
data[it+aux_it][2] = np
data[it+aux_it][3] = np_par
data[it+aux_it][4] = ns
data[it+aux_it][5] = dist
data[it+aux_it][6] = compute_tam
data[it+aux_it][7] = comm_tam
data[it+aux_it][8] = time
data[it+aux_it][9] = iters
data[it+aux_it][10] = float(observation)
aux_it+=1
elif it_line==1:
for observation in lineS:
data[it+aux_it][11] = float(observation)
aux_it+=1
else:
for observation in lineS:
data[it+aux_it][12] = float(observation)
aux_it+=1
it_line += 1
if(it_line % 3 == 0): # Comprobar si se ha terminado de mirar esta ejecucion
recording = False
it_line = 0
it = it + aux_it
if lineS[0] == "Config:":
compute_tam = int(lineS[1].split('=')[1].split(',')[0])
comm_tam = int(lineS[2].split('=')[1].split(',')[0])
sdr = int(lineS[3].split('=')[1].split(',')[0])
adr = int(lineS[4].split('=')[1].split(',')[0])
time = float(lineS[6].split('=')[1])
elif lineS[0] == "Config":
recording = True
iters = int(lineS[2].split('=')[1].split(',')[0])
dist = int(lineS[4].split('=')[1].split(',')[0])
np = int(lineS[5].split('=')[1].split(',')[0])
np_par = int(lineS[6].split('=')[1].split(',')[0])
ns = int(float(lineS[7].split('=')[1]))
return it
#-----------------------------------------------
#Config: matrix=1000, sdr=1000000000, adr=0, aib=0 time=2.000000
#Config Group: iters=100, factor=1.000000, phy=2, procs=2, parents=0, sons=4
#Ttype: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
if len(sys.argv) < 2:
print("The files name is missing\nUsage: python3 iterTimes.py resultsName directory csvOutName")
exit(1)
if len(sys.argv) >= 3:
BaseDir = sys.argv[2]
print("Searching in directory: "+ BaseDir)
else:
BaseDir = sys.argv[2]
if len(sys.argv) >= 4:
print("Csv name will be: " + sys.argv[3] + ".csv")
name = sys.argv[3]
else:
name = "data"
insideDir = "Run"
lista = glob.glob("./" + BaseDir + insideDir + "*/" + sys.argv[1]+ "*ID*.o*")
print("Number of files found: "+ str(len(lista)));
it = 0
data = [] #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12
columns = ["N", "%Async", "NP", "N_par", "NS", "Dist", "Compute_tam", "Comm_tam", "Time", "Iters", "Ti", "Tt", "To"] #13
for elem in lista:
f = open(elem, "r")
it = read_file(f, data, it)
f.close()
#print(data)
df = pd.DataFrame(data, columns=columns)
df['N'] += df['%Async']
df['%Async'] = (df['%Async'] / df['N']) * 100
df.to_csv(name + '.csv')
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment