diff --git a/icfree/learner/README.md b/icfree/learner/README.md new file mode 100644 index 0000000..e69de29 diff --git a/icfree/learner/__init__.py b/icfree/learner/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/icfree/learner/__init__.py @@ -0,0 +1 @@ + diff --git a/icfree/learner/active_loop.py b/icfree/learner/active_loop.py new file mode 100644 index 0000000..830599c --- /dev/null +++ b/icfree/learner/active_loop.py @@ -0,0 +1,143 @@ +import argparse +import numpy as np +import pandas as pd +import warnings +from sklearn.exceptions import ConvergenceWarning +from sklearn.preprocessing import MaxAbsScaler +warnings.filterwarnings("ignore", category=ConvergenceWarning) + +from library.utils import * +from library.model import * +from library.active_learning import * + + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Script for active learning and model training.") + + # Add all the arguments that were previously loaded from config.csv and use the CSV values as defaults + parser.add_argument('--name_list', type=str, default='Yield1,Yield2,Yield3,Yield4,Yield5', help="Comma-separated list of names") + parser.add_argument('--nb_rep', type=int, default=100, help="Number of repetitions") + parser.add_argument('--flatten', type=str, choices=['true', 'false'], default='False', help="Whether to flatten data") + parser.add_argument('--seed', type=int, default=85, help="Random seed") + parser.add_argument('--nb_new_data_predict', type=int, default=3000, help="Number of new data points to predict") + parser.add_argument('--nb_new_data', type=int, default=50, help="Number of new data points") + parser.add_argument('--parameter_step', type=int, default=20, help="Parameter step") + parser.add_argument('--test', type=int, default=1, help="Test flag") + parser.add_argument('--n_group', type=int, default=15, help="Number of groups") + parser.add_argument('--ks', type=int, default=20, help="ks parameter") + parser.add_argument('--km', type=int, default=50, help="km parameter") + parser.add_argument('--plot', type=str, choices=['true', 'false'], default='True', help="Whether to plot the results") + parser.add_argument('--data_folder', type=str, default='data/top50', help="Folder containing data") + parser.add_argument('--parameter_file', type=str, default='param.tsv', help="Parameter file path") + parser.add_argument('--save_name', type=str, default='new_exp/plate3', help="Name for saving outputs") + + args = parser.parse_args() + + # Convert boolean-like strings to actual booleans + args.flatten = args.flatten.lower() == 'true' + args.plot = args.plot.lower() == 'true' + + # Convert comma-separated lists to actual Python lists + args.name_list = args.name_list.split(',') + + return args + +def main(): + args = parse_arguments() + + data_folder = args.data_folder + name_list = args.name_list + parameter_file = args.parameter_file + nb_rep = args.nb_rep + flatten = args.flatten + seed = args.seed + nb_new_data_predict = args.nb_new_data_predict + nb_new_data = args.nb_new_data + parameter_step = args.parameter_step + test = args.test + save_name = args.save_name + n_group = args.n_group + ks = args.ks + km = args.km + plot = args.plot + + # Proceed with the rest of the script logic + element_list, element_max, sampling_condition = import_parameter(parameter_file, parameter_step) + + data, size_list = import_data(data_folder, verbose = True) + check_column_names(data,element_list) + + no_element = len(element_list) + y = np.array(data[name_list]) + y_mean = np.nanmean(y, axis = 1) + y_std = np.nanstd(y, axis = 1) + X = data.iloc[:,0:no_element] + + params = {'kernel': [ + C()*Matern(length_scale=10, nu=2.5)+ WhiteKernel(noise_level=1e-3, noise_level_bounds=(1e-3, 1e1)) + ], + # 'alpha':[0.01, 0.025, 0.05, 0.075, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5]} + 'alpha':[0.05]} + + X_train, X_test, y_train, y_test = split_and_flatten(X, y, ratio = 0, flatten = flatten) + scaler = MaxAbsScaler() + X_train_norm = scaler.fit_transform(X_train) + model = BayesianModels(n_folds= 10, model_type = 'gp', params=params) + model.train(X_train_norm, y_train) + + if test: + best_param = {'alpha': [model.best_params['alpha']],'kernel': [model.best_params['kernel']]} + res = [] + for i in range(nb_rep): + X_train, X_test, y_train, y_test = split_and_flatten(X, y, ratio = 0.2, flatten = flatten) + + scaler = MaxAbsScaler() + X_train_norm = scaler.fit_transform(X_train) + X_test_norm = scaler.transform(X_test) + + eva_model = BayesianModels(model_type ='gp', params= best_param) + eva_model.train(X_train_norm, y_train, verbose = False) + y_pred, std_pred = eva_model.predict(X_test_norm) + res.append(r2_score(y_test, y_pred)) + + plt.hist(res, bins = 20, color='orange') + plt.title(f'Histogram of R2 for different testing subset, median= {np.median(res):.2f}', size = 12) + + X_new= sampling_without_repeat(sampling_condition, num_samples = nb_new_data_predict, existing_data=X_train, seed = seed) + X_new_norm = scaler.transform(X_new) + y_pred, std_pred = model.predict(X_new_norm) + clusters = cluster(X_new_norm, n_group) + + ei = expected_improvement(y_pred, std_pred, max(y_train)) + print("For EI:") + ei_top, y_ei, ratio_ei, ei_cluster = find_top_elements(X_new, y_pred, clusters, ei, km, return_ratio= True) + ei_top_norm = scaler.transform(ei_top) + + if plot: + plot_selected_point(y_pred, std_pred, y_ei, 'EI selected') + + size_list.append(nb_new_data) + y_mean = np.append(y_mean, y_ei) + plot_each_round(y_mean,size_list, predict = True) + + plot_train_test(X_train_norm, ei_top_norm, element_list) + + fig, axes = plt.subplots(1, 1, figsize=(10, 4)) + plot_heatmap(axes, ei_top_norm, y_ei, element_list, 'EI') + plt.tight_layout() + plt.xlabel("Yield: left-low, right-high") + plt.show() + + X_ei = pd.DataFrame(ei_top, columns=element_list) + name = save_name + '_ei'+ str(km) + '.csv' + X_ei.to_csv(name, index=False) + + +if __name__ == "__main__": + main() + + + + + + diff --git a/icfree/learner/calibrator.py b/icfree/learner/calibrator.py new file mode 100644 index 0000000..398cbf4 --- /dev/null +++ b/icfree/learner/calibrator.py @@ -0,0 +1,222 @@ +import pandas as pd +import argparse +import numpy as np +import statsmodels.api as sm +import matplotlib.pyplot as plt +import os +import random + +def calculate_yield(data: pd.DataFrame, jove_plus_line: int, jove_minus_line: int) -> pd.DataFrame: + # Adjust the line numbers because of the header row (subtracting an additional 1 for zero-based indexing) + jove_plus_index = jove_plus_line - 2 + jove_minus_index = jove_minus_line - 2 + + # Get the autofluorescence and reference values based on user input + autofluorescence = data.iloc[jove_minus_index].filter(like='Fluorescence').mean() + reference = data.iloc[jove_plus_index].filter(like='Fluorescence').mean() + + # Create yield columns for each fluorescence value + for col in data.columns: + if 'Fluorescence' in col: + yield_col = col.replace('Fluorescence', 'Yield') + data[yield_col] = (data[col] - autofluorescence) / (reference - autofluorescence) + + return data + +def add_calibrated_yield(data: pd.DataFrame, a: float, b: float) -> pd.DataFrame: + # Add "Calibrated Yield" columns for each "Yield" column + for col in data.columns: + if 'Yield' in col and 'Calibrated' not in col: + calibrated_yield_col = col.replace('Yield', 'Calibrated Yield') + data[calibrated_yield_col] = a * data[col] + b + + return data + +def fit_regression_with_outlier_removal(y: np.ndarray, y_ref: np.ndarray, r2_limit: float) -> tuple: + max_outliers = int(0.3 * len(y)) # 30% of data points can be considered outliers + current_r2 = 0 + num_outliers_removed = 0 + + outlier_indices = [] + + while current_r2 <= r2_limit and num_outliers_removed < max_outliers: + print(f"Current R²: {current_r2:.2f}, r2_limit: {r2_limit:.2f}, Outliers removed: {num_outliers_removed}") + # Add a constant term for OLS + X = sm.add_constant(y) + model = sm.OLS(y_ref, X).fit() + current_r2 = model.rsquared + + # Calculate Cook's distance + influence = model.get_influence() + cooks_d = influence.cooks_distance[0] + + # Identify the index of the maximum Cook's distance + max_cooks_index = np.argmax(cooks_d) + + # Add the index to outlier list and remove it from the data + outlier_indices.append(max_cooks_index) + y = np.delete(y, max_cooks_index) + y_ref = np.delete(y_ref, max_cooks_index) + num_outliers_removed += 1 + + # Fit the final model + final_model = sm.OLS(y_ref, sm.add_constant(y)).fit() + a, b = final_model.params[1], final_model.params[0] + r2_value = final_model.rsquared + + return a, b, r2_value, outlier_indices + +def select_control_points(data: pd.DataFrame, jove_plus_index: int, jove_minus_index: int, n: int) -> pd.DataFrame: + # Find the index of the point with the highest yield + max_yield_index = data.filter(like='Yield').mean(axis=1).idxmax() + + # Select Jove+, Jove-, and the point with the highest yield + control_indices = {jove_plus_index, jove_minus_index, max_yield_index} + + # Select additional random points to reach n control points + remaining_indices = list(set(data.index) - control_indices) + random_indices = random.sample(remaining_indices, n - 3) + control_indices.update(random_indices) + + # Return the DataFrame with the selected control points + return data.loc[list(control_indices)] + +def plot_calibrated_points(y: np.ndarray, y_ref: np.ndarray, outlier_indices: list, a: float, b: float, r2_value: float, output_file: str, input_filename: str, ref_filename: str): + # Plot the calibrated points in blue and outliers in red + plt.figure(figsize=(10, 6)) + plt.scatter(y, y_ref, color='blue', label='Calibrated Points') + if outlier_indices: + plt.scatter(y[outlier_indices], y_ref[outlier_indices], color='red', label='Removed Outliers') + # Plot the regression line ax + b + x_vals = np.array([min(y), max(y)]) + y_vals = a * x_vals + b + plt.plot(x_vals, y_vals, color='green', label=f'Regression Line: y = {a:.2f}x + {b:.2f}, R² = {r2_value:.2f}') + # Add axis labels with filenames + plt.xlabel(f'Calibrated Yield ({os.path.basename(input_filename)})') + plt.ylabel(f'Reference Yield ({os.path.basename(ref_filename)})') + plt.title('Calibrated Points with Outliers Removed and Regression Line') + plt.legend() + plt.savefig(output_file, format='png') + plt.close() + +def detect_component_columns(data: pd.DataFrame) -> list: + # Detect columns that appear before the first "Fluorescence" column + component_columns = [] + for col in data.columns: + if 'Fluorescence' in col: + break + component_columns.append(col) + return component_columns + +def find_matching_indices(input_data: pd.DataFrame, ref_data: pd.DataFrame, component_columns: list, rounding_precision: int = 2) -> tuple: + # Round component values before matching + input_combinations = input_data[component_columns].round(rounding_precision).apply(tuple, axis=1) + ref_combinations = ref_data[component_columns].round(rounding_precision).apply(tuple, axis=1) + + # Convert reference combinations to a set for efficient matching + ref_combinations_set = set(ref_combinations) + + # Find indices where the component combinations match + matching_input_indices = [] + matching_ref_indices = [] + + for i, combination in enumerate(input_combinations): + if combination in ref_combinations_set: + # Find the corresponding index in the reference data + ref_index = ref_combinations[ref_combinations == combination].index[0] + matching_input_indices.append(i) + matching_ref_indices.append(ref_index) + + return matching_input_indices, matching_ref_indices + +def compute_average_yields(modified_data: pd.DataFrame, ref_data: pd.DataFrame, matching_input_indices: list, matching_ref_indices: list) -> tuple: + # Calculate the average yield for the matching component combinations + avg_yield = modified_data.filter(like='Yield').iloc[matching_input_indices].mean(axis=1).values + avg_yield_ref = ref_data.filter(like='Yield').iloc[matching_ref_indices].mean(axis=1).values + return avg_yield, avg_yield_ref + +def load_data(file_path: str) -> pd.DataFrame: + # Load data based on file extension + if file_path.endswith('.xlsx'): + return pd.read_excel(file_path, sheet_name=0) # Read the first sheet + elif file_path.endswith('.csv'): + return pd.read_csv(file_path) + else: + raise ValueError("Unsupported file format. Please provide a .csv or .xlsx file.") + +def save_data(data: pd.DataFrame, output_file: str): + # Save data based on file extension + if output_file.endswith('.xlsx'): + data.to_excel(output_file, index=False) + elif output_file.endswith('.csv'): + data.to_csv(output_file, index=False) + else: + raise ValueError("Unsupported file format. Please specify a .csv or .xlsx output file.") + +if __name__ == "__main__": + # Set up argument parsing + parser = argparse.ArgumentParser(description='Calculate yield based on fluorescence data and optionally apply calibration.') + parser.add_argument('--file', type=str, required=True, help='Path to the input file (.csv or .xlsx)') + parser.add_argument('--jove_plus', type=int, required=True, help='Line number for Jove+ (1-based index)') + parser.add_argument('--jove_minus', type=int, required=True, help='Line number for Jove- (1-based index)') + parser.add_argument('--r2_limit', type=float, default=0.8, help='R-squared limit for the regression (default: 0.8)') + parser.add_argument('--ref_file', type=str, help='Path to the reference input file (.csv or .xlsx)') + parser.add_argument('--output', type=str, required=True, help='Output file name (.csv or .xlsx)') + parser.add_argument('--plot', type=str, help='Output PNG file name for the plot of calibrated points') + parser.add_argument('--num_control_points', type=int, default=10, help='Number of control points to select (default: 5)') + + args = parser.parse_args() + + # Load the data from the input file + input_data = load_data(args.file) + + # Calculate the yield and get the modified DataFrame + modified_data = calculate_yield(input_data, args.jove_plus, args.jove_minus) + + # Detect component columns + component_columns = detect_component_columns(modified_data) + + # Check if a reference file is provided + if args.ref_file: + # Load the reference data + ref_data = load_data(args.ref_file) + + # Find matching indices based on component combinations + matching_input_indices, matching_ref_indices = find_matching_indices(modified_data, ref_data, component_columns) + + # Compute average yields for matching component combinations + avg_yield, avg_yield_ref = compute_average_yields(modified_data, ref_data, matching_input_indices, matching_ref_indices) + + # Fit the regression with outlier removal on average yields + a, b, r2_value, outlier_indices = fit_regression_with_outlier_removal(avg_yield, avg_yield_ref, args.r2_limit) + + # Display the regression coefficients and R² value in the terminal + print(f"Regression Line: y = {a:.2f}x + {b:.2f}") + print(f"R² Value: {r2_value:.2f}") + + # Add calibrated yield columns + calibrated_data = add_calibrated_yield(modified_data, a, b) + + # Plot the calibrated points with outliers and regression line if requested + if args.plot: + plot_calibrated_points(avg_yield, avg_yield_ref, outlier_indices, a, b, r2_value, args.plot, args.file, args.ref_file) + else: + # If no reference file is provided, just use the original + calibrated_data = modified_data + + # Save the modified DataFrame to the specified output file + save_data(calibrated_data, args.output) + print(f"Calibrated yields saved in {args.output}") + if args.plot: + print(f"Plot saved as {args.plot}") + + # Select control points + jove_plus_index = args.jove_plus - 2 + jove_minus_index = args.jove_minus - 2 + control_data = select_control_points(modified_data, jove_plus_index, jove_minus_index, args.num_control_points) + + # Save the new control points + outf = os.path.splitext(args.output)[0] + '_control_points.csv' + save_data(control_data, outf) + print(f"New control points saved in {outf}") + diff --git a/icfree/learner/config.csv b/icfree/learner/config.csv new file mode 100644 index 0000000..6848ad8 --- /dev/null +++ b/icfree/learner/config.csv @@ -0,0 +1,19 @@ +param,value +data_folder,data/top50 +name_list,"Yield1,Yield2,Yield3,Yield4,Yield5" +parameter_file,param.tsv +nb_rep,100 +flatten,False +seed,85 +nb_new_data_predict,3000 +nb_new_data,50 +parameter_step,20 +strategy,ei +theta,10 +save_name,new_exp/plate3 +n_group,15 +km,50 +ks,20 +plot,True +test,1 + diff --git a/icfree/learner/data/top20/plate0.csv b/icfree/learner/data/top20/plate0.csv new file mode 100644 index 0000000..2170bf2 --- /dev/null +++ b/icfree/learner/data/top20/plate0.csv @@ -0,0 +1,103 @@ +Mg-glutamate,K-glutamate,Amino acid,Spermidine,Creatine Phosphate,NTP,GFP11_Col-E1,GFP1-10,PEG-8000,Yield1,Yield2,Yield3 +0.0,40.0,1100.0,120.0,40.0,40.0,380.0,760.0,120.0,0.272188282784596,0.312789461354093,0.28694743291705 +40.0,0.0,660.0,120.0,300.0,20.0,80.0,900.0,1320.0,0.454488115189851,0.388531473572291,0.392586185147141 +0.0,160.0,640.0,80.0,920.0,0.0,20.0,180.0,360.0,0.0108486060802653,0.0138220612351553,0.0100917265862933 +60.0,580.0,700.0,40.0,540.0,80.0,140.0,660.0,940.0,0.697554558396857,0.48206015389883,0.935160656683066 +40.0,240.0,160.0,120.0,880.0,100.0,720.0,960.0,100.0,0.0224721125948352,0.0117136112162333,0.0224721125948352 +0.0,20.0,420.0,100.0,360.0,120.0,500.0,760.0,340.0,0.391234614622191,0.381611432484547,0.350146870663711 +0.0,320.0,640.0,20.0,220.0,100.0,340.0,1200.0,360.0,1.18444432430484,1.21509794381071,1.21953109513254 +60.0,440.0,120.0,80.0,380.0,60.0,720.0,840.0,420.0,0.597970842118542,0.317925429348903,0.396424645437999 +80.0,860.0,680.0,20.0,140.0,0.0,60.0,760.0,1020.0,0.372961381124867,0.357823791245427,0.338361175686147 +80.0,340.0,920.0,80.0,360.0,0.0,800.0,120.0,440.0,0.125894289164009,0.109405128759619,0.0710745886720369 +40.0,540.0,460.0,100.0,840.0,20.0,860.0,580.0,620.0,0.054315114162657,0.0235533690147952,0.0199311600079292 +40.0,800.0,280.0,0.0,820.0,20.0,680.0,1160.0,1300.0,0.0836712259645708,0.0280405831576292,0.0373934511902831 +0.0,520.0,720.0,120.0,400.0,60.0,240.0,820.0,460.0,0.585428267647006,0.29775999711665,0.288731506009984 +20.0,0.0,420.0,0.0,260.0,80.0,380.0,300.0,1240.0,0.345010902668901,0.243859364581644,0.248076264619488 +20.0,120.0,100.0,120.0,640.0,60.0,380.0,800.0,1280.0,2.06247860013336,0.788596348957489,0.529797624840064 +40.0,780.0,340.0,80.0,20.0,40.0,760.0,1020.0,0.0,1.10151195689391,0.484168603917752,0.55504496224613 +80.0,80.0,640.0,20.0,940.0,0.0,700.0,1040.0,1200.0,0.157791353552828,0.0982141248130328,0.140220936728479 +40.0,640.0,300.0,140.0,460.0,80.0,840.0,700.0,380.0,0.944946027283704,0.724802220179849,0.0379340794002631 +20.0,440.0,260.0,100.0,180.0,120.0,420.0,600.0,700.0,0.80611270296084,1.17936241913103,1.03625813194933 +20.0,900.0,400.0,60.0,580.0,100.0,20.0,20.0,880.0,0.00219855472058532,0.00198230343659333,0.00733452271539529 +0.0,100.0,320.0,140.0,280.0,100.0,840.0,460.0,1280.0,0.317384801138923,0.874177794597322,0.947432917049612 +60.0,100.0,500.0,80.0,520.0,40.0,180.0,360.0,1120.0,0.0842659169955488,0.30073345227154,0.263862608350904 +0.0,540.0,40.0,140.0,280.0,120.0,380.0,1020.0,560.0,1.4640572345065,1.20266349498117,1.0586401398425 +80.0,0.0,640.0,100.0,640.0,0.0,360.0,960.0,160.0,0.205366636031068,0.188715287163684,0.171144870339334 +60.0,680.0,100.0,60.0,840.0,80.0,240.0,580.0,1080.0,0.172820817790272,0.20531257321007,0.051449784649763 +0.0,480.0,240.0,140.0,540.0,100.0,540.0,460.0,1200.0,1.2694851417347,1.33263051666036,1.66895532608892 +0.0,80.0,640.0,80.0,500.0,100.0,260.0,820.0,1000.0,0.400533419833847,0.387720531257321,0.310626948514173 +40.0,680.0,240.0,100.0,700.0,0.0,620.0,940.0,800.0,0.0923212773242508,0.0932403452812168,0.0751833630678849 +60.0,880.0,960.0,0.0,240.0,100.0,40.0,360.0,120.0,0.0459894397289651,0.0982681876340308,0.059126705231479 +0.0,800.0,20.0,40.0,480.0,0.0,540.0,1060.0,1080.0,0.194932511578454,0.122326142978141,0.107512930024689 +0.0,500.0,240.0,20.0,80.0,80.0,80.0,680.0,1060.0,1.30624786001334,0.876826872826224,1.09426753888018 +0.0,20.0,340.0,0.0,620.0,20.0,180.0,960.0,220.0,0.455461245967815,0.377286406804707,0.313708529311059 +20.0,400.0,720.0,120.0,40.0,120.0,200.0,720.0,820.0,1.29278621758483,1.25342848389829,1.04804382692689 +20.0,320.0,280.0,140.0,360.0,40.0,840.0,740.0,1120.0,0.668576886341929,0.658629327278297,0.977978410913481 +0.0,600.0,100.0,40.0,160.0,100.0,60.0,820.0,1180.0,1.81762808383341,1.62727289109946,1.26332198014092 +40.0,40.0,760.0,140.0,600.0,140.0,700.0,1000.0,20.0,0.0931322196392208,0.0938350363121948,0.108269809518661 +60.0,960.0,400.0,0.0,920.0,20.0,280.0,1240.0,280.0,0.0151736317601052,0.0120920509632193,0.0110648573642573 +80.0,700.0,100.0,140.0,920.0,60.0,80.0,420.0,80.0,0.000846984195635332,0.000955109837631332,0.00236074318357932 +60.0,420.0,420.0,40.0,120.0,120.0,560.0,240.0,900.0,0.0306355985655332,0.141356255969436,0.484817357769728 +40.0,520.0,700.0,100.0,160.0,20.0,740.0,200.0,920.0,0.0856715503414968,0.113405777513471,0.191148114108594 +60.0,440.0,680.0,100.0,140.0,60.0,240.0,40.0,820.0,0.049341334630841,0.0942675388801788,0.0902128273053288 +0.0,20.0,160.0,60.0,580.0,60.0,500.0,460.0,600.0,0.468220071723343,0.478924510280946,0.377286406804707 +40.0,800.0,1020.0,0.0,440.0,100.0,720.0,60.0,1200.0,0.0769133733398209,0.128543367392911,0.127137734046963 +40.0,800.0,680.0,140.0,700.0,120.0,540.0,740.0,860.0,0.651168657980573,0.247589699230506,0.506496548989926 +80.0,200.0,160.0,80.0,780.0,140.0,680.0,120.0,580.0,0.0193905317979492,0.0115514227532393,0.0158764484330792 +60.0,520.0,1000.0,0.0,20.0,80.0,460.0,620.0,80.0,0.446270566398155,0.543583644194554,0.159034798435782 +20.0,80.0,600.0,100.0,560.0,40.0,80.0,1020.0,460.0,0.061775783460381,0.0446378692040151,0.0317168549854931 +80.0,900.0,620.0,120.0,660.0,120.0,260.0,460.0,320.0,0.206285703988034,0.0693986412210989,0.225532068263322 +80.0,860.0,920.0,60.0,440.0,0.0,100.0,960.0,1140.0,0.230830224721126,0.1855796435458,0.24261591969869 +80.0,180.0,500.0,20.0,360.0,80.0,560.0,520.0,500.0,0.339063992359121,0.559748427672956,0.28938025986196 +40.0,460.0,980.0,80.0,460.0,0.0,40.0,840.0,1200.0,0.135247157196663,0.123731776324089,0.186552774323764 +0.0,840.0,20.0,80.0,260.0,40.0,680.0,220.0,1080.0,0.0351228127083671,0.123569587861095,0.0781027554017769 +60.0,300.0,320.0,40.0,480.0,60.0,380.0,1140.0,20.0,0.135084968733669,0.233479302950028,0.206772269377016 +80.0,940.0,900.0,120.0,60.0,100.0,20.0,120.0,880.0,0.0959975491521148,0.212935430970788,0.173523634463246 +60.0,100.0,1060.0,100.0,120.0,40.0,260.0,1240.0,320.0,0.117947054477303,0.24964408642843,0.19422969490548 +80.0,800.0,1060.0,120.0,640.0,20.0,860.0,840.0,680.0,0.0245805626137572,0.0256077562127192,0.0277702690526392 +80.0,60.0,720.0,0.0,120.0,40.0,40.0,780.0,900.0,0.159683552287758,0.211205420698852,0.187958407669712 +60.0,960.0,1100.0,0.0,740.0,20.0,180.0,80.0,780.0,0.00933484709232128,0.0405831576291651,0.0173902074210232 +80.0,660.0,620.0,140.0,840.0,80.0,820.0,280.0,180.0,0.0232289920888072,0.0960516119731128,0.0120379881422213 +60.0,480.0,420.0,40.0,400.0,20.0,660.0,720.0,880.0,0.0813465246616568,0.0682633219801409,0.058045448811519 +40.0,680.0,500.0,60.0,940.0,20.0,120.0,480.0,520.0,0.0055504496224613,0.00711827143140329,0.00760483682038529 +80.0,380.0,280.0,0.0,100.0,100.0,60.0,1240.0,120.0,0.486817682146654,0.160332306139734,0.272945162278568 +0.0,180.0,1060.0,80.0,840.0,0.0,520.0,160.0,300.0,0.000901047016633332,0.00100917265862933,-0.000937088897298657 +20.0,820.0,640.0,40.0,260.0,80.0,600.0,640.0,320.0,0.965111459515958,0.539204555693716,1.07945432592673 +0.0,980.0,160.0,60.0,480.0,100.0,780.0,860.0,1320.0,0.647708637436701,1.22937052855418,1.37815141194068 +60.0,360.0,780.0,80.0,220.0,40.0,480.0,900.0,20.0,0.481195148762862,0.2180173361446,0.406426267322629 +40.0,980.0,800.0,140.0,520.0,80.0,420.0,120.0,1240.0,0.149573804761132,0.339874934674091,0.301922834333496 +20.0,480.0,0.0,140.0,160.0,120.0,840.0,960.0,1300.0,0.142275323926402,0.106810113351715,0.173631760105242 +40.0,460.0,1000.0,60.0,600.0,20.0,220.0,1180.0,1060.0,0.0889153196013768,0.0300949703555532,0.0454488115189851 +40.0,160.0,1000.0,80.0,160.0,80.0,820.0,620.0,1020.0,0.782919752752699,0.804490818330901,1.49941431943919 +80.0,680.0,760.0,20.0,0.0,20.0,840.0,1180.0,1260.0,0.347227478329819,0.426321385449893,0.448162765133085 +60.0,420.0,760.0,20.0,200.0,20.0,500.0,660.0,160.0,0.1477356688472,0.0962138004361068,0.121731451947163 +0.0,660.0,620.0,140.0,100.0,100.0,540.0,960.0,480.0,1.3613378746103,2.04690850768593,2.53185201203799 +60.0,140.0,420.0,80.0,420.0,80.0,840.0,280.0,460.0,0.234019931160008,0.363932890018201,0.21720639382963 +60.0,800.0,880.0,60.0,40.0,80.0,860.0,1120.0,880.0,1.84411886612243,1.87942188823413,1.12935430970788 +80.0,200.0,740.0,20.0,120.0,140.0,120.0,800.0,580.0,0.756266782000685,0.945540718314682,0.860229586779838 +40.0,740.0,140.0,120.0,180.0,60.0,100.0,1000.0,840.0,1.09215908886126,0.547368041664414,0.657439945216341 +0.0,480.0,880.0,120.0,280.0,0.0,40.0,660.0,1060.0,0.179686796057018,0.107188553098701,0.147789731668198 +20.0,540.0,60.0,140.0,580.0,20.0,260.0,620.0,1240.0,0.339820871853093,0.124650844281055,0.223910183633382 +80.0,60.0,460.0,20.0,540.0,20.0,180.0,420.0,280.0,0.120001441675227,0.0974572453190607,0.109188877475627 +0.0,940.0,1100.0,0.0,240.0,20.0,840.0,400.0,1000.0,0.139139680308519,0.134598403344687,0.157791353552828 +40.0,160.0,580.0,120.0,840.0,140.0,820.0,1200.0,180.0,0.0164170766430592,0.0103079778702853,0.0158764484330792 +0.0,580.0,460.0,120.0,500.0,120.0,160.0,760.0,900.0,1.13984249698149,0.983006253266296,1.28305490980519 +40.0,840.0,840.0,100.0,60.0,100.0,840.0,800.0,1300.0,1.35187688093565,0.814168063289542,2.71961218936404 +20.0,20.0,1080.0,40.0,60.0,40.0,740.0,1080.0,960.0,0.30641004847633,0.281865527743238,0.252293164657332 +60.0,440.0,520.0,140.0,180.0,40.0,380.0,520.0,260.0,0.22477518876935,0.277702690526392,0.377502658088699 +80.0,560.0,400.0,40.0,140.0,120.0,460.0,1000.0,500.0,1.10253915049287,1.75232019606783,2.31111351390316 +80.0,940.0,440.0,60.0,580.0,0.0,640.0,1140.0,640.0,0.223531743886396,0.217260456650628,0.178443351174064 +0.0,940.0,260.0,60.0,880.0,120.0,520.0,1140.0,220.0,0.0357715665603431,0.0399884665981871,0.00722639707339929 +40.0,920.0,980.0,60.0,100.0,60.0,320.0,960.0,300.0,0.923915589915482,1.13995062262349,1.07712962462381 +60.0,900.0,560.0,0.0,160.0,60.0,360.0,820.0,940.0,1.16649546773351,1.77670252833793,1.79324575156332 +20.0,840.0,420.0,60.0,840.0,0.0,520.0,1240.0,440.0,0.111405453136545,0.120866446811195,0.136058099511633 +80.0,560.0,1020.0,60.0,40.0,120.0,220.0,340.0,480.0,0.781081616838767,0.177308031933106,0.86233803679876 +60.0,380.0,960.0,20.0,440.0,40.0,680.0,420.0,200.0,0.0961597376151088,0.0836712259645708,0.333549584617325 +20.0,540.0,240.0,120.0,560.0,20.0,660.0,860.0,160.0,0.063127353985331,0.048854769241859,0.0838874772485628 +20.0,980.0,1040.0,0.0,260.0,40.0,840.0,600.0,1080.0,0.256564127516174,0.418914778973167,0.606188390910238 +80.0,20.0,220.0,0.0,300.0,80.0,700.0,220.0,1140.0,0.476599808978032,0.55774810329603,0.434052368852607 +60.0,200.0,480.0,120.0,300.0,120.0,100.0,300.0,1100.0,0.942729451622786,0.274837361013498,0.353012200176605 +60.0,660.0,1020.0,100.0,540.0,40.0,0.0,120.0,1140.0,0.0134976843091673,0.0058748265484493,0.00782108810437729 +60.0,400.0,60.0,0.0,420.0,120.0,740.0,920.0,100.0,0.192013119244562,0.289164008577968,0.117136112162333 +52.5,770.0,875.0,105.0,625.0,102.5,857.5,1237.5,1050.0,1.43107891369772,1.37966517092862,0.189255915373664 +52.5,770.0,875.0,105.0,625.0,102.5,0.0,0.0,1050.0,0.00322574831954732,0.00273918293056532,-0.00596493125011263 \ No newline at end of file diff --git a/icfree/learner/data/top20/plate1.csv b/icfree/learner/data/top20/plate1.csv new file mode 100644 index 0000000..9582c19 --- /dev/null +++ b/icfree/learner/data/top20/plate1.csv @@ -0,0 +1,21 @@ +Mg-glutamate,K-glutamate,Amino acid,Spermidine,Creatine Phosphate,NTP,GFP11_Col-E1,GFP1-10,PEG-8000,Yield1,Yield2,Yield3,Yield4,Yield5,Yield6 +20.0,920.0,380.0,120.0,600.0,140.0,380.0,1220.0,1020.0,0.686,0.391,0.332,0.413,0.333,1.047 +80.0,780.0,1060.0,100.0,80.0,100.0,860.0,680.0,1000.0,1.911,0.928,1.292,1.462,2.198,2.078 +80.0,500.0,960.0,20.0,100.0,100.0,500.0,1200.0,580.0,1.862,1.377,1.973,1.428,1.78,1.823 +40.0,620.0,1080.0,120.0,220.0,80.0,480.0,1120.0,900.0,2.549,1.442,2.267,2.27,2.038,2.934 +80.0,480.0,200.0,140.0,120.0,140.0,460.0,1220.0,980.0,2.105,1.38,1.8,1.836,1.353,2.21 +60.0,920.0,520.0,80.0,60.0,80.0,760.0,1240.0,1220.0,2.445,1.821,2.707,2.402,2.62,2.726 +60.0,780.0,720.0,40.0,60.0,120.0,480.0,980.0,1120.0,1.312,0.414,1.858,2.149,1.653,1.937 +20.0,660.0,600.0,60.0,240.0,120.0,500.0,1080.0,900.0,2.262,1.432,2.408,2.258,1.591,1.848 +80.0,700.0,720.0,100.0,340.0,100.0,780.0,1020.0,960.0,2.579,1.662,2.097,3.392,2.926,2.948 +40.0,340.0,800.0,40.0,20.0,80.0,300.0,860.0,1280.0,0.486,0.431,0.439,0.56,0.279,0.191 +20.0,740.0,1060.0,60.0,80.0,60.0,800.0,820.0,940.0,1.102,0.997,1.02,1.437,1.273,2.299 +40.0,760.0,340.0,20.0,40.0,120.0,400.0,800.0,280.0,2.121,1.656,1.947,1.625,1.511,2.07 +20.0,760.0,900.0,140.0,160.0,60.0,840.0,980.0,1140.0,2.435,1.945,2.468,1.889,1.357,2.136 +60.0,560.0,1060.0,40.0,80.0,120.0,580.0,1220.0,1300.0,1.349,1.225,1.279,1.388,1.217,0.945 +40.0,940.0,420.0,60.0,80.0,120.0,380.0,860.0,560.0,2.179,2.214,1.931,3.407,2.279,2.455 +40.0,920.0,640.0,80.0,120.0,80.0,20.0,1060.0,400.0,0.16,0.128,0.139,0.137,0.186,0.204 +20.0,760.0,200.0,20.0,20.0,140.0,380.0,840.0,80.0,0.369,1.95,1.873,1.376,1.927,2.193 +60.0,400.0,720.0,140.0,140.0,140.0,740.0,1240.0,620.0,2.926,2.005,1.448,1.668,1.549,1.831 +80.0,620.0,1020.0,60.0,200.0,140.0,360.0,1240.0,540.0,1.984,1.807,1.728,1.811,1.262,1.147 +20.0,680.0,1080.0,40.0,80.0,140.0,540.0,880.0,640.0,1.184,1.092 diff --git a/icfree/learner/data/top50/plate0.csv b/icfree/learner/data/top50/plate0.csv new file mode 100644 index 0000000..2170bf2 --- /dev/null +++ b/icfree/learner/data/top50/plate0.csv @@ -0,0 +1,103 @@ +Mg-glutamate,K-glutamate,Amino acid,Spermidine,Creatine Phosphate,NTP,GFP11_Col-E1,GFP1-10,PEG-8000,Yield1,Yield2,Yield3 +0.0,40.0,1100.0,120.0,40.0,40.0,380.0,760.0,120.0,0.272188282784596,0.312789461354093,0.28694743291705 +40.0,0.0,660.0,120.0,300.0,20.0,80.0,900.0,1320.0,0.454488115189851,0.388531473572291,0.392586185147141 +0.0,160.0,640.0,80.0,920.0,0.0,20.0,180.0,360.0,0.0108486060802653,0.0138220612351553,0.0100917265862933 +60.0,580.0,700.0,40.0,540.0,80.0,140.0,660.0,940.0,0.697554558396857,0.48206015389883,0.935160656683066 +40.0,240.0,160.0,120.0,880.0,100.0,720.0,960.0,100.0,0.0224721125948352,0.0117136112162333,0.0224721125948352 +0.0,20.0,420.0,100.0,360.0,120.0,500.0,760.0,340.0,0.391234614622191,0.381611432484547,0.350146870663711 +0.0,320.0,640.0,20.0,220.0,100.0,340.0,1200.0,360.0,1.18444432430484,1.21509794381071,1.21953109513254 +60.0,440.0,120.0,80.0,380.0,60.0,720.0,840.0,420.0,0.597970842118542,0.317925429348903,0.396424645437999 +80.0,860.0,680.0,20.0,140.0,0.0,60.0,760.0,1020.0,0.372961381124867,0.357823791245427,0.338361175686147 +80.0,340.0,920.0,80.0,360.0,0.0,800.0,120.0,440.0,0.125894289164009,0.109405128759619,0.0710745886720369 +40.0,540.0,460.0,100.0,840.0,20.0,860.0,580.0,620.0,0.054315114162657,0.0235533690147952,0.0199311600079292 +40.0,800.0,280.0,0.0,820.0,20.0,680.0,1160.0,1300.0,0.0836712259645708,0.0280405831576292,0.0373934511902831 +0.0,520.0,720.0,120.0,400.0,60.0,240.0,820.0,460.0,0.585428267647006,0.29775999711665,0.288731506009984 +20.0,0.0,420.0,0.0,260.0,80.0,380.0,300.0,1240.0,0.345010902668901,0.243859364581644,0.248076264619488 +20.0,120.0,100.0,120.0,640.0,60.0,380.0,800.0,1280.0,2.06247860013336,0.788596348957489,0.529797624840064 +40.0,780.0,340.0,80.0,20.0,40.0,760.0,1020.0,0.0,1.10151195689391,0.484168603917752,0.55504496224613 +80.0,80.0,640.0,20.0,940.0,0.0,700.0,1040.0,1200.0,0.157791353552828,0.0982141248130328,0.140220936728479 +40.0,640.0,300.0,140.0,460.0,80.0,840.0,700.0,380.0,0.944946027283704,0.724802220179849,0.0379340794002631 +20.0,440.0,260.0,100.0,180.0,120.0,420.0,600.0,700.0,0.80611270296084,1.17936241913103,1.03625813194933 +20.0,900.0,400.0,60.0,580.0,100.0,20.0,20.0,880.0,0.00219855472058532,0.00198230343659333,0.00733452271539529 +0.0,100.0,320.0,140.0,280.0,100.0,840.0,460.0,1280.0,0.317384801138923,0.874177794597322,0.947432917049612 +60.0,100.0,500.0,80.0,520.0,40.0,180.0,360.0,1120.0,0.0842659169955488,0.30073345227154,0.263862608350904 +0.0,540.0,40.0,140.0,280.0,120.0,380.0,1020.0,560.0,1.4640572345065,1.20266349498117,1.0586401398425 +80.0,0.0,640.0,100.0,640.0,0.0,360.0,960.0,160.0,0.205366636031068,0.188715287163684,0.171144870339334 +60.0,680.0,100.0,60.0,840.0,80.0,240.0,580.0,1080.0,0.172820817790272,0.20531257321007,0.051449784649763 +0.0,480.0,240.0,140.0,540.0,100.0,540.0,460.0,1200.0,1.2694851417347,1.33263051666036,1.66895532608892 +0.0,80.0,640.0,80.0,500.0,100.0,260.0,820.0,1000.0,0.400533419833847,0.387720531257321,0.310626948514173 +40.0,680.0,240.0,100.0,700.0,0.0,620.0,940.0,800.0,0.0923212773242508,0.0932403452812168,0.0751833630678849 +60.0,880.0,960.0,0.0,240.0,100.0,40.0,360.0,120.0,0.0459894397289651,0.0982681876340308,0.059126705231479 +0.0,800.0,20.0,40.0,480.0,0.0,540.0,1060.0,1080.0,0.194932511578454,0.122326142978141,0.107512930024689 +0.0,500.0,240.0,20.0,80.0,80.0,80.0,680.0,1060.0,1.30624786001334,0.876826872826224,1.09426753888018 +0.0,20.0,340.0,0.0,620.0,20.0,180.0,960.0,220.0,0.455461245967815,0.377286406804707,0.313708529311059 +20.0,400.0,720.0,120.0,40.0,120.0,200.0,720.0,820.0,1.29278621758483,1.25342848389829,1.04804382692689 +20.0,320.0,280.0,140.0,360.0,40.0,840.0,740.0,1120.0,0.668576886341929,0.658629327278297,0.977978410913481 +0.0,600.0,100.0,40.0,160.0,100.0,60.0,820.0,1180.0,1.81762808383341,1.62727289109946,1.26332198014092 +40.0,40.0,760.0,140.0,600.0,140.0,700.0,1000.0,20.0,0.0931322196392208,0.0938350363121948,0.108269809518661 +60.0,960.0,400.0,0.0,920.0,20.0,280.0,1240.0,280.0,0.0151736317601052,0.0120920509632193,0.0110648573642573 +80.0,700.0,100.0,140.0,920.0,60.0,80.0,420.0,80.0,0.000846984195635332,0.000955109837631332,0.00236074318357932 +60.0,420.0,420.0,40.0,120.0,120.0,560.0,240.0,900.0,0.0306355985655332,0.141356255969436,0.484817357769728 +40.0,520.0,700.0,100.0,160.0,20.0,740.0,200.0,920.0,0.0856715503414968,0.113405777513471,0.191148114108594 +60.0,440.0,680.0,100.0,140.0,60.0,240.0,40.0,820.0,0.049341334630841,0.0942675388801788,0.0902128273053288 +0.0,20.0,160.0,60.0,580.0,60.0,500.0,460.0,600.0,0.468220071723343,0.478924510280946,0.377286406804707 +40.0,800.0,1020.0,0.0,440.0,100.0,720.0,60.0,1200.0,0.0769133733398209,0.128543367392911,0.127137734046963 +40.0,800.0,680.0,140.0,700.0,120.0,540.0,740.0,860.0,0.651168657980573,0.247589699230506,0.506496548989926 +80.0,200.0,160.0,80.0,780.0,140.0,680.0,120.0,580.0,0.0193905317979492,0.0115514227532393,0.0158764484330792 +60.0,520.0,1000.0,0.0,20.0,80.0,460.0,620.0,80.0,0.446270566398155,0.543583644194554,0.159034798435782 +20.0,80.0,600.0,100.0,560.0,40.0,80.0,1020.0,460.0,0.061775783460381,0.0446378692040151,0.0317168549854931 +80.0,900.0,620.0,120.0,660.0,120.0,260.0,460.0,320.0,0.206285703988034,0.0693986412210989,0.225532068263322 +80.0,860.0,920.0,60.0,440.0,0.0,100.0,960.0,1140.0,0.230830224721126,0.1855796435458,0.24261591969869 +80.0,180.0,500.0,20.0,360.0,80.0,560.0,520.0,500.0,0.339063992359121,0.559748427672956,0.28938025986196 +40.0,460.0,980.0,80.0,460.0,0.0,40.0,840.0,1200.0,0.135247157196663,0.123731776324089,0.186552774323764 +0.0,840.0,20.0,80.0,260.0,40.0,680.0,220.0,1080.0,0.0351228127083671,0.123569587861095,0.0781027554017769 +60.0,300.0,320.0,40.0,480.0,60.0,380.0,1140.0,20.0,0.135084968733669,0.233479302950028,0.206772269377016 +80.0,940.0,900.0,120.0,60.0,100.0,20.0,120.0,880.0,0.0959975491521148,0.212935430970788,0.173523634463246 +60.0,100.0,1060.0,100.0,120.0,40.0,260.0,1240.0,320.0,0.117947054477303,0.24964408642843,0.19422969490548 +80.0,800.0,1060.0,120.0,640.0,20.0,860.0,840.0,680.0,0.0245805626137572,0.0256077562127192,0.0277702690526392 +80.0,60.0,720.0,0.0,120.0,40.0,40.0,780.0,900.0,0.159683552287758,0.211205420698852,0.187958407669712 +60.0,960.0,1100.0,0.0,740.0,20.0,180.0,80.0,780.0,0.00933484709232128,0.0405831576291651,0.0173902074210232 +80.0,660.0,620.0,140.0,840.0,80.0,820.0,280.0,180.0,0.0232289920888072,0.0960516119731128,0.0120379881422213 +60.0,480.0,420.0,40.0,400.0,20.0,660.0,720.0,880.0,0.0813465246616568,0.0682633219801409,0.058045448811519 +40.0,680.0,500.0,60.0,940.0,20.0,120.0,480.0,520.0,0.0055504496224613,0.00711827143140329,0.00760483682038529 +80.0,380.0,280.0,0.0,100.0,100.0,60.0,1240.0,120.0,0.486817682146654,0.160332306139734,0.272945162278568 +0.0,180.0,1060.0,80.0,840.0,0.0,520.0,160.0,300.0,0.000901047016633332,0.00100917265862933,-0.000937088897298657 +20.0,820.0,640.0,40.0,260.0,80.0,600.0,640.0,320.0,0.965111459515958,0.539204555693716,1.07945432592673 +0.0,980.0,160.0,60.0,480.0,100.0,780.0,860.0,1320.0,0.647708637436701,1.22937052855418,1.37815141194068 +60.0,360.0,780.0,80.0,220.0,40.0,480.0,900.0,20.0,0.481195148762862,0.2180173361446,0.406426267322629 +40.0,980.0,800.0,140.0,520.0,80.0,420.0,120.0,1240.0,0.149573804761132,0.339874934674091,0.301922834333496 +20.0,480.0,0.0,140.0,160.0,120.0,840.0,960.0,1300.0,0.142275323926402,0.106810113351715,0.173631760105242 +40.0,460.0,1000.0,60.0,600.0,20.0,220.0,1180.0,1060.0,0.0889153196013768,0.0300949703555532,0.0454488115189851 +40.0,160.0,1000.0,80.0,160.0,80.0,820.0,620.0,1020.0,0.782919752752699,0.804490818330901,1.49941431943919 +80.0,680.0,760.0,20.0,0.0,20.0,840.0,1180.0,1260.0,0.347227478329819,0.426321385449893,0.448162765133085 +60.0,420.0,760.0,20.0,200.0,20.0,500.0,660.0,160.0,0.1477356688472,0.0962138004361068,0.121731451947163 +0.0,660.0,620.0,140.0,100.0,100.0,540.0,960.0,480.0,1.3613378746103,2.04690850768593,2.53185201203799 +60.0,140.0,420.0,80.0,420.0,80.0,840.0,280.0,460.0,0.234019931160008,0.363932890018201,0.21720639382963 +60.0,800.0,880.0,60.0,40.0,80.0,860.0,1120.0,880.0,1.84411886612243,1.87942188823413,1.12935430970788 +80.0,200.0,740.0,20.0,120.0,140.0,120.0,800.0,580.0,0.756266782000685,0.945540718314682,0.860229586779838 +40.0,740.0,140.0,120.0,180.0,60.0,100.0,1000.0,840.0,1.09215908886126,0.547368041664414,0.657439945216341 +0.0,480.0,880.0,120.0,280.0,0.0,40.0,660.0,1060.0,0.179686796057018,0.107188553098701,0.147789731668198 +20.0,540.0,60.0,140.0,580.0,20.0,260.0,620.0,1240.0,0.339820871853093,0.124650844281055,0.223910183633382 +80.0,60.0,460.0,20.0,540.0,20.0,180.0,420.0,280.0,0.120001441675227,0.0974572453190607,0.109188877475627 +0.0,940.0,1100.0,0.0,240.0,20.0,840.0,400.0,1000.0,0.139139680308519,0.134598403344687,0.157791353552828 +40.0,160.0,580.0,120.0,840.0,140.0,820.0,1200.0,180.0,0.0164170766430592,0.0103079778702853,0.0158764484330792 +0.0,580.0,460.0,120.0,500.0,120.0,160.0,760.0,900.0,1.13984249698149,0.983006253266296,1.28305490980519 +40.0,840.0,840.0,100.0,60.0,100.0,840.0,800.0,1300.0,1.35187688093565,0.814168063289542,2.71961218936404 +20.0,20.0,1080.0,40.0,60.0,40.0,740.0,1080.0,960.0,0.30641004847633,0.281865527743238,0.252293164657332 +60.0,440.0,520.0,140.0,180.0,40.0,380.0,520.0,260.0,0.22477518876935,0.277702690526392,0.377502658088699 +80.0,560.0,400.0,40.0,140.0,120.0,460.0,1000.0,500.0,1.10253915049287,1.75232019606783,2.31111351390316 +80.0,940.0,440.0,60.0,580.0,0.0,640.0,1140.0,640.0,0.223531743886396,0.217260456650628,0.178443351174064 +0.0,940.0,260.0,60.0,880.0,120.0,520.0,1140.0,220.0,0.0357715665603431,0.0399884665981871,0.00722639707339929 +40.0,920.0,980.0,60.0,100.0,60.0,320.0,960.0,300.0,0.923915589915482,1.13995062262349,1.07712962462381 +60.0,900.0,560.0,0.0,160.0,60.0,360.0,820.0,940.0,1.16649546773351,1.77670252833793,1.79324575156332 +20.0,840.0,420.0,60.0,840.0,0.0,520.0,1240.0,440.0,0.111405453136545,0.120866446811195,0.136058099511633 +80.0,560.0,1020.0,60.0,40.0,120.0,220.0,340.0,480.0,0.781081616838767,0.177308031933106,0.86233803679876 +60.0,380.0,960.0,20.0,440.0,40.0,680.0,420.0,200.0,0.0961597376151088,0.0836712259645708,0.333549584617325 +20.0,540.0,240.0,120.0,560.0,20.0,660.0,860.0,160.0,0.063127353985331,0.048854769241859,0.0838874772485628 +20.0,980.0,1040.0,0.0,260.0,40.0,840.0,600.0,1080.0,0.256564127516174,0.418914778973167,0.606188390910238 +80.0,20.0,220.0,0.0,300.0,80.0,700.0,220.0,1140.0,0.476599808978032,0.55774810329603,0.434052368852607 +60.0,200.0,480.0,120.0,300.0,120.0,100.0,300.0,1100.0,0.942729451622786,0.274837361013498,0.353012200176605 +60.0,660.0,1020.0,100.0,540.0,40.0,0.0,120.0,1140.0,0.0134976843091673,0.0058748265484493,0.00782108810437729 +60.0,400.0,60.0,0.0,420.0,120.0,740.0,920.0,100.0,0.192013119244562,0.289164008577968,0.117136112162333 +52.5,770.0,875.0,105.0,625.0,102.5,857.5,1237.5,1050.0,1.43107891369772,1.37966517092862,0.189255915373664 +52.5,770.0,875.0,105.0,625.0,102.5,0.0,0.0,1050.0,0.00322574831954732,0.00273918293056532,-0.00596493125011263 \ No newline at end of file diff --git a/icfree/learner/data/top50/plate1.csv b/icfree/learner/data/top50/plate1.csv new file mode 100644 index 0000000..619a6de --- /dev/null +++ b/icfree/learner/data/top50/plate1.csv @@ -0,0 +1,51 @@ +Mg-glutamate,K-glutamate,Amino acid,Spermidine,Creatine Phosphate,NTP,GFP11_Col-E1,GFP1-10,PEG-8000,Yield1,Yield2,Yield3,Yield4,Yield5,Yield6 +60.0,780,720,40,60,120.0,480.0,980.0,1120,1.312475523,0.4137787951,1.857978808,2.149257862,1.653004658,1.937247987 +20.0,660,600,60,240,120.0,500.0,1080.0,900,2.262298525,1.432082864,2.408172577,2.25807709,1.59109027,1.847659743 +40.0,940,420,60,80,120.0,380.0,860.0,560,2.179276959,2.213986541,1.931150357,3.406776613,2.278715219,2.454608368 +60.0,560,1060,40,80,120.0,580.0,1220.0,1300,1.349061298,1.224763472,1.278704038,1.387992314,1.217258698,0.9452106282 +20.0,680,1080,40,80,140.0,540.0,880.0,640,1.18442531,1.092491825,0.9555296929,0.9602201769,0.4245669082,1.803569194 +80.0,620,1020,60,200,140.0,360.0,1240.0,540,1.984152826,1.807321581,1.727583353,1.81060492,1.261818296,1.146901439 +60.0,920,520,80,60,80.0,760.0,1240.0,1220,2.444758352,1.820923984,2.706956405,2.401605899,2.619713403,2.726187389 +80.0,760,480,40,140,100.0,780.0,1080.0,820,3.033883137,1.870174066,1.448030509,1.672235643,2.067174392,3.072345106 +80.0,960,660,60,60,120.0,680.0,660.0,920,2.065298199,1.273075457,1.102341841,1.319511249,1.988374262,2.485096514 +20.0,640,340,100,80,100.0,360.0,960.0,660,1.937717035,2.235093718,1.899724115,2.153948346,2.045129118,2.65864442 +80.0,900,840,60,460,140.0,580.0,1060.0,940,2.242129444,1.657695142,1.838747823,1.819047791,1.469137687,0.7064649944 +60.0,820,200,40,40,80.0,420.0,920.0,1220,1.160034794,1.996817133,1.512290139,1.59109027,1.603754577,1.728052402 +20.0,600,600,100,40,120.0,840.0,720.0,520,1.448968606,1.167539568,0.9391129991,0.7838579798,0.8232580451,1.796064419 +20.0,760,900,140,160,60.0,840.0,980.0,1140,2.434908335,1.944752761,2.468210771,1.888936002,1.356566072,2.135655458 +40.0,700,680,100,440,140.0,500.0,1120.0,1140,2.303105736,2.402543996,2.266050913,2.293724768,1.470544832,1.65253561 +60.0,400,720,140,140,140.0,740.0,1240.0,620,2.925532958,2.004790956,1.448030509,1.668483255,1.549344963,1.831243049 +20.0,940,360,80,80,120.0,480.0,540.0,900,2.942887749,1.791842984,1.420356654,0.6182838959,1.170822907,1.645968932 +80.0,500,960,20,100,100.0,500.0,1200.0,580,1.862200243,1.377204201,1.973364713,1.428330477,1.780116774,1.823269226 +20.0,520,540,140,200,140.0,680.0,1180.0,200,1.923176535,1.605161722,2.181622201,2.507141788,1.859855001,2.508548933 +40.0,620,1080,120,220,80.0,480.0,1120.0,900,2.549356144,1.44193288,2.266989009,2.2698033,2.037624343,2.933975829 +40.0,880,720,120,260,140.0,660.0,680.0,900,1.440994783,0.839674739,1.751035773,1.438649541,2.131903071,2.261360429 +80.0,780,1060,100,80,100.0,860.0,680.0,1000,1.911450325,0.9278558375,1.291837393,1.462101961,2.198038895,2.077962506 +40.0,960,780,60,480,120.0,400.0,1180.0,440,0.2993309863,0.8321699647,0.3898573269,0.7505555437,0.5207218295,0.923634402 +80.0,480,200,140,120,140.0,460.0,1220.0,980,2.105167313,1.380018492,1.799816806,1.836402581,1.353282733,2.210234153 +40.0,700,400,120,40,60.0,660.0,1180.0,620,1.163318133,1.519325865,1.428799525,1.539963995,1.496342494,1.815764452 +20.0,880,460,40,340,100.0,700.0,1140.0,460,1.52683064,1.212099166,1.450375751,1.455535284,1.669421352,2.013702875 +40.0,760,340,20,40,120.0,400.0,800.0,280,2.12064591,1.656287997,1.946628955,1.624861755,1.511352043,2.070457731 +20.0,760,200,20,20,140.0,380.0,840.0,80,0.3692191974,1.949912293,1.873457405,1.375797056,1.92739797,2.193348411 +80.0,720,580,20,280,120.0,500.0,640.0,1260,2.217738928,1.433959057,1.727114305,2.189126976,1.303094555,2.523089434 +80.0,680,220,40,320,100.0,220.0,1020.0,860,2.453670271,1.997286181,1.743530999,0.8241961419,1.782462016,1.440525735 +40.0,200,560,140,40,100.0,680.0,1160.0,1040,0.09717112749,0.07840919164,0.1454831123,0.1051449502,0.083568724,0.09294969192 +40.0,500,940,60,340,140.0,620.0,740.0,800,1.913326518,1.841093065,1.903476502,1.624392706,0.5221289746,1.759478644 +20.0,920,380,120,600,140.0,380.0,1220.0,1020,0.685826865,0.3907954236,0.3316953257,0.4128406983,0.3326334225,1.046525082 +40.0,320,120,20,180,120.0,120.0,980.0,780,0.7735389151,0.7735389151,1.176920536,0.8326390131,0.7683793828,0.9606892253 +80.0,700,720,100,340,100.0,780.0,1020.0,960,2.579375241,1.662385626,2.096724441,3.392236112,2.926471055,2.947578233 +20.0,580,360,80,220,120.0,840.0,1080.0,300,2.036217198,1.551690205,1.584992641,2.241660396,1.062003679,1.844376404 +60.0,80,1020,140,60,100.0,700.0,980.0,820,0.1285973701,0.2430451788,0.1769093549,0.3668739554,0.2219380009,0.3945478108 +80.0,900,460,20,280,140.0,800.0,660.0,340,0.6239124767,1.558725931,1.217258698,1.820923984,1.461163864,2.18209125 +80.0,640,1100,20,600,140.0,300.0,920.0,800,0.8598438201,0.7388293338,0.6492410901,0.5136861035,0.4372312149,0.3542096487 +20.0,740,1060,60,80,60.0,800.0,820.0,940,1.101872793,0.9968059518,1.019789323,1.437242396,1.272606409,2.2988843 +40.0,340,800,40,20,80.0,300.0,860.0,1280,0.4864812965,0.4311335857,0.4391074085,0.5596528464,0.2786928569,0.1914498552 +20.0,680,560,100,200,100.0,560.0,820.0,360,1.247277796,1.207408682,1.063879873,1.29277549,1.471951977,1.440994783 +80.0,400,220,120,40,120.0,300.0,860.0,720,0.7238197851,0.54980283,0.6412672673,0.6994292685,0.6220362831,0.6745697035 +40.0,920,640,80,120,80.0,20.0,1060.0,400,0.160492661,0.1276592733,0.1389164348,0.1365711928,0.1858212744,0.2041141619 +80.0,620,640,80,660,120.0,80.0,1160.0,1320,0.4301954889,0.5104027647,0.5422980557,0.4785074738,0.4400455053,0.5132170551 +40.0,460,760,60,340,140.0,300.0,780.0,900,0.3504572616,1.726645257,1.612197448,1.747752434,1.408630444,1.721954773 +80.0,920,100,80,180,60.0,700.0,1100.0,1320,0.6614363484,1.367354185,1.177389584,1.272606409,1.273544506,1.027294098 +60.0,920,400,100,100,40.0,700.0,1140.0,1240,0.425505005,0.9850797419,1.156282407,1.667545159,1.440994783,1.137051422 +20.0,720,1020,20,80,60.0,80.0,1080.0,580,0.4583383927,0.8134080288,0.3968930528,0.4344169245,0.4151859403,0.7228816883 +60.0,420,20,60,360,120.0,340.0,920.0,1060,0.742581721,0.76040556,1.032922678,1.05872034,0.8926772078,1.018851226 \ No newline at end of file diff --git a/icfree/learner/environment.yaml b/icfree/learner/environment.yaml new file mode 100644 index 0000000..4119bb1 --- /dev/null +++ b/icfree/learner/environment.yaml @@ -0,0 +1,18 @@ +name: active +channels: + - conda-forge + - defaults +dependencies: + - numpy + - pandas + - scikit-learn + - matplotlib + - seaborn + - xgboost + - scipy + - ipython + - ipywidgets + - glob2 + - pip + - pip: + - warnings diff --git a/icfree/learner/extractor.py b/icfree/learner/extractor.py new file mode 100644 index 0000000..ecb1814 --- /dev/null +++ b/icfree/learner/extractor.py @@ -0,0 +1,177 @@ +import pandas as pd +import argparse + +def find_n_m(sampling_file_path): + """ + Find the number of unique combinations (n) and the number of replicates (m) from a sampling file. + + Parameters: + sampling_file_path (str): Path to the sampling file (Excel, CSV, or TSV). + + Returns: + tuple: A tuple containing the number of unique combinations (n) and the number of replicates (m). + """ + # Load the sampling file + df_sampling = pd.read_csv(sampling_file_path, sep='\t') + + # Drop the unnamed column if it exists + if df_sampling.columns[0].startswith('Unnamed'): + df_sampling = df_sampling.drop(columns=df_sampling.columns[0]) + + # Identify unique combinations (n) and replicates (m) + unique_combinations = df_sampling.drop_duplicates() + n = unique_combinations.shape[0] + m = df_sampling.shape[0] // n + + return n, m + +def process_data(file_path, num_samples, num_replicates): + """ + Process the initial data file to reshape the fluorescence data. + + Parameters: + file_path (str): Path to the initial data file (Excel, CSV, or TSV). + num_samples (int): Number of samples. + num_replicates (int): Number of replicates. + + Returns: + tuple: A tuple containing the reshaped DataFrame and the sheet name (if applicable). + """ + # Determine the file extension + file_extension = file_path.split('.')[-1].lower() + + # Load the data based on file extension + if file_extension == 'xlsx': + excel_data = pd.ExcelFile(file_path) + sheet_name = excel_data.sheet_names[0] + df = pd.read_excel(file_path, sheet_name=sheet_name) + elif file_extension == 'csv': + df = pd.read_csv(file_path) + sheet_name = None + elif file_extension == 'tsv': + df = pd.read_csv(file_path, sep='\t') + sheet_name = None + else: + raise ValueError("Unsupported file type. Please provide an Excel (.xlsx), CSV (.csv), or TSV (.tsv) file.") + + # Keep only the last row and remove the first two columns + df_last_row = df.iloc[[-1]].drop(columns=df.columns[:2]) + + # Keep only the required number of values + total_values = num_samples * num_replicates + values_to_keep = df_last_row.values.flatten()[:total_values] + + # Reshape the values into the specified number of columns and rows + reshaped_values = values_to_keep.reshape((num_samples, num_replicates), order='F') + + # Create a new DataFrame with the reshaped values + df_reshaped = pd.DataFrame(reshaped_values) + + # Add headers to the reshaped DataFrame + headers = [f"Fluorescence Value {i+1}" for i in range(num_replicates)] + df_reshaped.columns = headers + + # Add "Fluorescence Average" column + df_reshaped["Fluorescence Average"] = df_reshaped.mean(axis=1) + + return df_reshaped, sheet_name + +def load_sampling_file(file_path, num_samples): + """ + Load the sampling file and take only the first num_samples lines. + + Parameters: + file_path (str): Path to the sampling file (Excel, CSV, or TSV). + num_samples (int): Number of samples to load. + + Returns: + DataFrame: A DataFrame containing the first num_samples lines of the sampling file. + """ + # Determine the file extension + file_extension = file_path.split('.')[-1].lower() + + # Load the data based on file extension + if file_extension == 'xlsx': + df = pd.read_excel(file_path) + elif file_extension == 'csv': + df = pd.read_csv(file_path) + elif file_extension == 'tsv': + df = pd.read_csv(file_path, sep='\t') + else: + raise ValueError("Unsupported file type. Please provide an Excel (.xlsx), CSV (.csv), or TSV (.tsv) file.") + + # Take only the first num_samples lines + df = df.head(num_samples) + + return df + +def clean_sampling_file(df_sampling): + """ + Clean the sampling file by removing the unnamed first column if it contains incrementing integers. + + Parameters: + df_sampling (DataFrame): The sampling DataFrame to clean. + + Returns: + DataFrame: The cleaned sampling DataFrame. + """ + first_column = df_sampling.iloc[:, 0] + if first_column.name.startswith('Unnamed') and pd.api.types.is_integer_dtype(first_column): + if (first_column == range(len(first_column))).all(): + df_sampling = df_sampling.drop(columns=first_column.name) + return df_sampling + +def process(initial_data_file, output_file_path, sampling_file, num_samples=None, num_replicates=None, display=True): + """ + Process the initial data file and sampling file to combine the data and save the output. + + Parameters: + initial_data_file (str): Path to the initial data file (Excel, CSV, or TSV). + output_file_path (str): Path for the output file. + sampling_file (str): Path to the sampling file (Excel, CSV, or TSV). + num_samples (int, optional): Number of samples. If not specified, it will be detected from the sampling file. + num_replicates (int, optional): Number of replicates. If not specified, it will be detected from the sampling file. + display (bool, optional): Whether to display the combined data. Default is True. + + Returns: + DataFrame: The combined DataFrame. + """ + if num_samples is None or num_replicates is None: + n, m = find_n_m(sampling_file) + num_samples = num_samples if num_samples is not None else n + num_replicates = num_replicates if num_replicates is not None else m + + df_reshaped, sheet_name = process_data(initial_data_file, num_samples, num_replicates) + + df_sampling = load_sampling_file(sampling_file, num_samples) + df_sampling_cleaned = clean_sampling_file(df_sampling) + df_combined = pd.concat([df_sampling_cleaned, df_reshaped], axis=1) + + if display: + print(df_combined) + + # Save the combined dataframe with headers and averages in the specified format + if output_file_path.endswith('.xlsx'): + df_combined.to_excel(output_file_path, index=False, sheet_name=sheet_name) + elif output_file_path.endswith('.csv'): + df_combined.to_csv(output_file_path, index=False) + elif output_file_path.endswith('.tsv'): + df_combined.to_csv(output_file_path, index=False, sep='\t') + else: + raise ValueError("Unsupported output file type. Please provide an Excel (.xlsx), CSV (.csv), or TSV (.tsv) file.") + + print(f"Processed data saved to {output_file_path}") + return df_combined + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Process and reshape fluorescence data.") + parser.add_argument("--initial_data_file", type=str, required=True, help="Path to the initial Excel, CSV, or TSV file.") + parser.add_argument("--output_file", type=str, required=True, help="Path for the output file.") + parser.add_argument("--sampling_file", type=str, required=True, help="Path to the sampling Excel, CSV, or TSV file.") + parser.add_argument("--num_samples", type=int, help="Number of samples.") + parser.add_argument("--num_replicates", type=int, help="Number of replicates.") + parser.add_argument("--no_display", action="store_true", help="Do not display the result.") + + args = parser.parse_args() + + process(args.initial_data_file, args.output_file, args.sampling_file, args.num_samples, args.num_replicates, not args.no_display) diff --git a/icfree/learner/library/active_learning.py b/icfree/learner/library/active_learning.py new file mode 100644 index 0000000..1ad7edd --- /dev/null +++ b/icfree/learner/library/active_learning.py @@ -0,0 +1,262 @@ +import numpy as np +from scipy.stats import norm +from scipy.cluster.hierarchy import dendrogram, linkage, fcluster +from matplotlib import pyplot as plt + + +def sample_new_combination(sampling_condition, nb_sample = 100000, seed=None): + """ + Generate random experiments by samples from each component of sampling_condition + Removes NaN values from each column before sampling and samples are drawn with replacement + + Parameters: + - sampling_condition (pandas.DataFrame): DataFrame containing all concentration/volume to pick + - nb_sample (int, optional): Number of samples to draw from each column. Default is 100000. + - seed (int, optional): Seed for the random number generator. Default is None. + + Returns: + - numpy.ndarray: An array where each row is a sample with values drawn from each column of the DataFrame. + + """ + sampled_data = [] + np.random.seed(seed) + for i in range(sampling_condition.shape[1]): + sample_pool = sampling_condition.iloc[:,i] + sample_pool = sample_pool[~np.isnan(sample_pool)] # remove nan if exits + drawn_samples = np.random.choice(sample_pool , size = nb_sample, replace = True) + sampled_data.append(drawn_samples) + sampled_data = np.array(sampled_data).transpose() + return sampled_data + + +def sampling_without_repeat(sampling_condition, num_samples, existing_data, seed=None): + """ + Generates a new set of samples based on the sampling condition, ensuring + that the generated samples do not repeat any of the existing data. + + Parameters: + - sampling_condition (pandas.DataFrame): DataFrame containing all concentration/volume to pick + - num_samples (int):The number of samples to generate initially + - existing_data (array-like or np.ndarray): + The existing data set to avoid repetitions with the new samples. + - seed (int, optional): Seed for the random generator to ensure reproducibility + If not provided, randomness will be uncontrolled. + + Returns: + - new_samples (np.ndarray): A new set of samples that do not repeat the existing data. + """ + if not isinstance(existing_data, np.ndarray): + existing_data = np.array(existing_data) + + new_samples = sample_new_combination(sampling_condition, num_samples, seed=seed) + + while True: + matches = np.all(new_samples[:, np.newaxis] == existing_data, axis=-1) + rows_to_drop = np.any(matches, axis=1) + + if not np.any(rows_to_drop): + break + + num_repeats = sum(rows_to_drop) + resampled = sample_new_combination(sampling_condition, num_samples=num_repeats, seed=None) + new_samples = new_samples[~rows_to_drop] + new_samples = np.concatenate([new_samples, resampled]) + + return new_samples + + +def find_top_elements(X, y, cluster_list, condition, n, return_ratio=False, verbose=True): + """ + Finds the top 'n' elements from X, y, and cluster_list based on the highest values in 'condition' + + Parameters: + - X (array-like or np.ndarray) + Feature matrix where rows represent samples and columns represent features + - y (array-like or np.ndarray) + Target values or outcomes corresponding to the samples in X + - cluster_list (list of int) + name of cluster corresponding to the samples in X + - condition (list) + EI / PI/ UCB score used to rank the informativeness of samples in X + - n (int) + Number of top samples to return based on the highest 'condition' scores + - return_ratio (bool, optional, default=False) + Whether to return the ratio of the top elements based on 'condition' + this is ratio between exploration and exploitation (only use when ucb as surrogate function) + - verbose : bool, optional, default=True + If True, prints the maximum value of the selected target 'y' + + Returns: + - choosen_X (np.ndarray): The top 'n' samples from X corresponding to the highest 'condition' values. + - choosen_y (np.ndarray): The target values 'y' corresponding to the top 'n' samples. + - ratio (list): The 'condition' values corresponding to the top 'n' samples. Returned only if return_ratio is True. + - choosen_cluster (array-like): The clusters corresponding to the top 'n' samples. + """ + if not isinstance(X, np.ndarray): + X = np.array(X) + if not isinstance(y, np.ndarray): + y = np.array(y) + + idx_top_n = np.argsort(-condition)[:n] + + choosen_X = X[idx_top_n, :] + choosen_y = y[idx_top_n] + choosen_cluster = np.array(cluster_list)[idx_top_n] + + if return_ratio: + ratio = condition[idx_top_n] + else: + ratio = [] + + if verbose: + print(f"Maximum yield prediction = {np.max(choosen_y)}") + + return choosen_X, choosen_y, ratio, choosen_cluster + + +def probability_of_improvement(mu, sigma, current_best): + """ + Calculate Probability of Improvement (PI) for Gaussian process predictions. + + Parameters: + - mu: Mean of the Gaussian process prediction. + - sigma: Standard deviation of the Gaussian process prediction. + - current_best: Current best observed value. + Returns: + - pi: Probability of Improvement. + """ + + # Avoid division by zero + sigma = sigma + 1e-4 + + # Calculate standard normal cumulative distribution function + z = (mu - current_best) / sigma + pi = norm.cdf(z) + + return pi + + +def expected_improvement(mu, sigma, current_best): + """ + Calculate Expected Improvement (EI) for Gaussian process predictions. + + Parameters: + - mu: Mean of the Gaussian process prediction. + - sigma: Standard deviation of the Gaussian process prediction. + - current_best: Current best observed value. + - epsilon: Small positive constant to avoid division by zero. + + Returns: + - ei: Expected Improvement. + """ + + # Avoid division by zero + sigma = sigma + 1e-4 + + # Calculate standard normal cumulative distribution function + z = (mu - current_best) / sigma + ei = (mu - current_best) * norm.cdf(z) + sigma * norm.pdf(z) + + return ei + +def upper_confident_bound(mu, sigma, theta, r2): + """ + Calculate UCB for Gaussian process predictions. + + Parameters: + - mu: Mean of the Gaussian process prediction. + - sigma: Standard deviation of the Gaussian process prediction. + - epsilon: Small positive constant to avoid division by zero. + + Returns: + - ucb: + """ + if r2 <= 0.8: + ucb = mu + theta*sigma + else: + ucb = mu + return ucb + + +def cluster(X, n_clusters, method='complete', plot=False): + """ + Performs hierarchical clustering on the given data and optionally plots the dendrogram. + + Parameters: + - X (np.ndarray): data to be clustered, where rows are samples and columns are features. + - n_clusters (int): The number of clusters to form. + - method (str, optional, default='complete'): + The linkage algorithm to use for hierarchical clustering. Options include: + 'single', 'complete', 'average', 'ward', etc. + - plot (bool, optional, default=False) + If True, plots the dendrogram of the hierarchical clustering. + + Returns: + - clusters (np.ndarray) + Cluster labels for each sample in X. An array of size (n_samples,). + """ + Z = linkage(X, method=method) + clusters = fcluster(Z, n_clusters, criterion='maxclust') + + if plot: + plt.figure(figsize=(10, 5)) + plt.title('Hierarchical Clustering Dendrogram') + plt.xlabel('Sample Index') + plt.ylabel('Distance') + dendrogram(Z) + plt.show() + + return clusters + + +def pick_by_cluster(chosen_clust, n_sample, seed=42, verbose=False): + """ + Selects data points based on round robin sampling: arrange cluster by size (small to big), + in each cluster sort sample based on their EI value, then chose one point out of each cluster by order, + in this way we prioritize chosing the points with the highest EI value from each cluster + until the specified number of samples is reached + + Parameters: + - chosen_clust (np.ndarray) + A 2D array where the first column contains cluster labels and the second column contains EI values + - n_sample (int): The number of samples to select. + - seed (int, optional, default=42) rndom seed for reproducibility + - verbose (bool, optional, default=False) + If True, prints information about each cluster and its size + Returns: + - selected_indices (list) + List of indices representing the selected data points, based on the highest EI from each cluster + """ + np.random.seed(seed) + cluster_info = {} + + for cluster_label in np.unique(chosen_clust[:, 0]): + indices = np.where(chosen_clust[:, 0] == cluster_label)[0] + ei_values = chosen_clust[indices, 1] + num_points = len(indices) + cluster_info[cluster_label] = {'indices': indices, 'ei_values': ei_values, 'num_points': num_points} + + sorted_clusters = sorted(cluster_info.items(), key=lambda x: x[1]['num_points'], reverse=False) + + if verbose: + for cluster_label, info in sorted_clusters: + print(f"Cluster {cluster_label}: {info['num_points']} points") + + selected_indices = [] + selected_count = 0 + + while selected_count < n_sample: + for cluster_label, info in sorted_clusters: + if info['indices'].size > 0: + highest_ei_index = np.argmax(info['ei_values']) + selected_index = info['indices'][highest_ei_index] + selected_indices.append(selected_index) + + info['indices'] = np.delete(info['indices'], highest_ei_index) + info['ei_values'] = np.delete(info['ei_values'], highest_ei_index) + + selected_count += 1 + if selected_count == n_sample: + break + + return selected_indices \ No newline at end of file diff --git a/icfree/learner/library/model.py b/icfree/learner/library/model.py new file mode 100644 index 0000000..f7a0915 --- /dev/null +++ b/icfree/learner/library/model.py @@ -0,0 +1,189 @@ +import numpy as np +import pandas as pd +from sklearn.neural_network import MLPRegressor +from sklearn.model_selection import GridSearchCV +from sklearn.ensemble import RandomForestRegressor +from xgboost import XGBRegressor +from sklearn.gaussian_process import GaussianProcessRegressor +from sklearn.gaussian_process.kernels import RBF, Matern, DotProduct, WhiteKernel +from sklearn.gaussian_process.kernels import ConstantKernel as C + +def predict_rf(model, X): + """ + Predict using a RandomForestRegressor model and return mean and standard deviation of predictions from all trees + + Parameters: + - model: RandomForestRegressor + The trained RandomForestRegressor model. + - X: array-like + The input features for prediction. + + Returns: + - mean: ndarray + Mean prediction across all trees. + - std: ndarray + Standard deviation of predictions across all trees. + """ + tree_predictions = np.array([tree.predict(X) for tree in model.estimators_]) + mean = np.mean(tree_predictions, axis=0) + std = np.std(tree_predictions, axis=0) + return mean, std + +def predict_gp(model, X): + """ + Predict using a GaussianProcessRegressor model and return mean and standard deviation of predictions. + + Parameters: + - model: GaussianProcessRegressor + The trained GaussianProcessRegressor model. + - X: array-like + The input features for prediction. + + Returns: + - mean: ndarray + Mean prediction. + - std: ndarray + Standard deviation of prediction. + """ + mean, std = model.predict(X, return_std=True) + return mean, std + +def predict_ensemble(models, X): + """ + Predict using an ensemble of models and return mean and standard deviation of ensemble predictions. + + Parameters: + - models: list of models + The list of trained models. + - X: array-like + The input features for prediction. + + Returns: + - pred_mean: ndarray + Mean prediction across all models. + - pred_std: ndarray + Standard deviation of predictions across all models. + """ + predictions = [model.predict(X).reshape(-1, 1) for model in models] + pred_std = np.std(predictions, axis=0).ravel() + pred_mean = np.mean(predictions, axis=0).ravel() + return pred_mean, pred_std + +class BayesianModels: + def __init__(self, n_folds=5, model_type='', params=None): + """ + Initialize the BayesianModels class with specified parameters. + + Parameters: + - n_folds: int, optional (default=5) + Number of folds for cross-validation. + - model_type: str, optional (default='') + The type of model to be used ('rf', 'xgboost', 'mlp', or 'gp'). + - params: dict, optional (default=None) + Parameters for model creation. If None, default parameters for Gaussian Process are used. + """ + self.n_folds = n_folds + self.model_type = model_type + self.models = [] + self.score = [] + if params is None: + self.params = { + 'kernel': [ + RBF() + WhiteKernel(), + DotProduct() + WhiteKernel(), + Matern(length_scale=1, nu=1.5) + WhiteKernel(), + RBF() + C() + WhiteKernel(), + Matern(length_scale=1, nu=1.5) + C() + WhiteKernel(), + Matern(length_scale=1, nu=1.5) + RBF() + WhiteKernel(), + Matern(length_scale=1, nu=1.5) + DotProduct() + WhiteKernel(), + RBF() + DotProduct() + WhiteKernel(), + RBF() * DotProduct() + WhiteKernel(), + RBF() + DotProduct() + C() + WhiteKernel(), + RBF() * DotProduct() + C() + WhiteKernel() + ] + } + self.model_type = 'gp' + else: + self.params = params + + def create(self, params=None): + """ + Create and return a model based on the specified model type and parameters. + + Parameters: + - params: dict, optional + Parameters to pass to the model constructor. + + Returns: + - model: sklearn or xgboost model + The instantiated model. + + Raises: + - ValueError: If an invalid model type is specified. + """ + model_types = { + 'rf': lambda: RandomForestRegressor(**params), + 'xgboost': lambda: XGBRegressor(**params), + 'mlp': lambda: MLPRegressor(**params), + 'gp': lambda: GaussianProcessRegressor(**params, optimizer="fmin_l_bfgs_b", n_restarts_optimizer=10) + } + + if self.model_type not in model_types: + raise ValueError("Invalid model type") + + return model_types[self.model_type]() + + def train(self, X, y, verbose=True): + """ + Train the model using GridSearchCV to find the best hyperparameters. + + Parameters: + - X: array-like + The input features for training. + - y: array-like + The target values for training. + - verbose: bool, optional (default=True) + Whether to print the best hyperparameters. + """ + if not isinstance(X, np.ndarray): + X = np.array(X) + if not isinstance(y, np.ndarray): + y = np.array(y) + + model = self.create(self.params) + grid_search = GridSearchCV(model, self.params, cv=self.n_folds, n_jobs=None, scoring='neg_root_mean_squared_error') + + grid_search.fit(X, y) + self.best_params = grid_search.best_params_ + self.cv_score = pd.DataFrame(grid_search.cv_results_) + + if verbose: + print(f"Best hyperparameter found: {self.best_params}") + + if self.model_type in ['gp', 'rf']: + model = self.create(params=self.best_params) + self.model = model.fit(X, y) + + if self.model_type in ['xgboost', 'mlp']: + self.model = [self.create(params=self.best_params).fit(X, y) for _ in range(20)] + + def predict(self, X): + """ + Predict using the trained model(s). + + Parameters: + - X: array-like + The input features for prediction. + + Returns: + - tuple of ndarray + Mean and standard deviation of predictions. + """ + model_dict = { + 'rf': lambda: predict_rf(self.model, X), + 'gp': lambda: predict_gp(self.model, X), + 'xgboost': lambda: predict_ensemble(self.model, X), + 'mlp': lambda: predict_ensemble(self.model, X) + } + + return model_dict[self.model_type]() diff --git a/icfree/learner/library/utils.py b/icfree/learner/library/utils.py new file mode 100644 index 0000000..488f484 --- /dev/null +++ b/icfree/learner/library/utils.py @@ -0,0 +1,406 @@ +import glob +import os +import numpy as np +import pandas as pd +import seaborn as sns +import matplotlib.pyplot as plt +from IPython.display import display +from sklearn.model_selection import train_test_split +from sklearn.metrics import r2_score + + +def import_data(folder_for_data, verbose = True): + """ + This function reads all CSV files in the specified folder, concatenates their contents + into a single DataFrame, and returns this DataFrame along with a list of number of data in each csv (row counts) for ploting later + If `verbose=True`, it prints the number of files processed, the names of the files, + and displays the concatenated DataFrame + Args: + folder_for_data (str): The path to the folder containing the CSV files. + verbose (bool, optional): If True, prints information about the files being processed + and displays the resulting DataFrame. Defaults to True. + + Returns: + concatenated_data (pd.DataFrame): containing the concatenated data from all CSV files + in the folder. The rows from each file are appended sequentially. + Noted the order of file impoerted is important because it will affect plotting later + list: A list of integers where each value represents the number of rows in each + CSV file that was processed. + + """ + + files = glob.glob(folder_for_data + "\\*.csv") + concatenated_data = pd.DataFrame() + size_list = [] + + for file in files: + df = pd.read_csv(file) + + # Check if columns are consistent across files + if concatenated_data.columns.empty: + concatenated_data = df + size_list.append(len(df)) + else: + concatenated_data = pd.concat([concatenated_data, df], ignore_index=True) + size_list.append(len(df)) + + if verbose: + print("Read ", len(files), " files: ") + for file in files: + data_name = os.path.basename(file) + print("- ", data_name) + display(concatenated_data) + + return concatenated_data, size_list + + +def import_parameter(parameter_file, parameter_step, sep='\t', verbose=False): + """ + Imports parameter data from a csv/tsv file and generates a DataFrame with sampling conditions for each element. + Condition ranging from `parameter_step` to the element's max value in increments of `parameter_step`, obmit 0 + + Args: + parameter_file (str): The path to the CSV file containing parameter data. + parameter_step (float): The step size used for generating ranges for each element's concentration. + sep (str, optional): The delimiter used in parameter file (';' , ',' , '\t') Defaults to '\t' + verbose (bool, optional): If True, prints detailed information about the loaded data and the resulting DataFrame. Defaults to False. + + Returns: + element_list (list): A list of element names from the 'Component' column of the CSV file. + element_max (list): A list of maximum values for each element from the 'maxValue' column of the CSV file. + sampling_condition (pd.DataFrame): A DataFrame containing the sampling conditions for each element, + where each column corresponds to an element, and rows represent the possible concentrations. + + """ + parameter = pd.read_csv(parameter_file, sep=sep) + element_list = parameter['Component'].to_list() + element_max = parameter['maxValue'].to_list() + + sampling_condition = pd.DataFrame([]) + for i in range(len(element_list)): + element_name = element_list[i] + element_pool = pd.Series( + np.arange(0, element_max[i] + parameter_step, parameter_step), + name=element_name + ) + sampling_condition = pd.concat([sampling_condition, element_pool], axis=1) + + sampling_condition = sampling_condition[1:] + + if verbose: + print(f"Element List: {element_list}") + print(f"Max Values: {element_max}") + print("Generated Sampling Conditions:") + display(sampling_condition) + + return element_list, element_max, sampling_condition + + +def check_column_names(data, element_list): + """ + Checks if the first n columns of the `data` DataFrame match the expected element list from parameter file. + + Args: + data (pd.DataFrame): The DataFrame containing the actual data with columns to be checked. + element_list (list): The list of expected element names (columns). + + Raises: + ValueError: If there are mismatched column names between the data and the element list. + """ + element_len = len(element_list) + element_data = data.columns[:element_len] + + columns_only_in_data = set(element_data).difference(element_list) + columns_only_in_parameter = set(element_list).difference(element_data) + + try: + if columns_only_in_data or columns_only_in_parameter: + print("- Columns only in data files:", columns_only_in_data) + print("- Columns only in parameter files:", columns_only_in_parameter) + raise ValueError("Column names are not matched, please modify parameter column names.") + else: + print("All column names matched successfully!") + + except ValueError as e: + error_message = f"{type(e).__name__}: {e}" + print("\033[1;91m{}\033[0m".format(error_message)) + + + +def flatten_X_y(feature_matrix, label_matrix): + """ + Flattens the input feature and label matrices, removing any entries where labels contain NaN values. + + Args: + feature_matrix (np.ndarray): A 2D array where each row represents a sample and columns are features. + label_matrix (np.ndarray): A 2D array where each row contains labels corresponding to the samples in `feature_matrix`. + + Returns: + flattened feature (np.ndarray): matrix with rows where labels contained NaN values removed. + flattened label (np.ndarray): labels array (y) with NaN values removed. + """ + flattened_features = [] + + for i in range(feature_matrix.shape[0]): + current_features = feature_matrix[i] + current_labels = label_matrix[i] + + for _ in current_labels: + flattened_features.append(current_features) + + flattened_features = np.array(flattened_features) + flattened_labels = np.array([label for sublist in label_matrix for label in sublist]) + + non_nan_indices = ~np.isnan(flattened_labels) + flattened_labels = flattened_labels[non_nan_indices] + flattened_features = flattened_features[non_nan_indices] + + return flattened_features, flattened_labels + + +def average_and_drop_na(feature_matrix, label_matrix): + """ + Averages the labels for each sample in the label matrix and removes any samples where the averaged label is NaN. + + Args: + feature_matrix (np.ndarray): A 2D array where each row represents a sample, and each column represents a feature. + label_matrix (list): each row contains multiple labels corresponding to the samples in `feature_matrix`. + + Returns: + filtered feature (np.ndarray): matrix with rows where the corresponding averaged label was NaN removed. + filtered_labels (np.ndarray): Averaged label array with NaN values removed. + """ + + if len(label_matrix) == 0: + return feature_matrix, label_matrix + + averaged_labels = np.nanmean(label_matrix, axis=1) + valid_indices = ~np.isnan(averaged_labels) + + filtered_features = feature_matrix[valid_indices] + filtered_labels = averaged_labels[valid_indices] + + return filtered_features, filtered_labels + + +def split_and_flatten(feature_matrix, label_array, ratio=0.2, seed=None, flatten=True): + """ + Splits the feature matrix and label array into training and testing sets, and flattens or averages the labels of only train set + + Args: + feature_matrix (np.ndarray): A 2D array where each row is a sample, and columns are features. + label_array (list of np.ndarray): A list of 1D arrays representing labels corresponding to each sample in `feature_matrix`. + ratio (float, optional): The proportion of data to include in the test split. Default is 0.2. + seed (int, optional): Seed for random splitting of data. Default is None. + flatten (bool, optional): If True, the labels are flattened. If False, the labels are averaged and NaNs are removed. Default is True. + + Returns: + X_train (np.ndarray): Training feature matrix. + X_test (np.ndarray): Test feature matrix. + y_train (np.ndarray): Training label array, flattened or averaged based on the `flatten` argument. + y_test (np.ndarray): Test label array, flattened. + """ + + feature_matrix = np.array(feature_matrix) + + max_len = len(max(label_array, key=len)) + label_array = np.array([np.pad(arr, (0, max_len - len(arr)), 'constant', constant_values=np.nan) for arr in label_array]) + + _, unique_indices = np.unique(feature_matrix, axis=0, return_index=True) + + if len(unique_indices) != len(feature_matrix): + print("WARNING: Repeated rows found in 'feature_matrix'. Unique rows will be used for splitting.") + + if ratio == 0: + X_train, X_test = feature_matrix, np.array([]) + y_train, y_test = label_array, np.array([]) + else: + train_indices, test_indices = train_test_split(unique_indices, test_size=ratio, random_state=seed) + X_train, X_test = feature_matrix[train_indices], feature_matrix[test_indices] + y_train = [label_array[i] for i in train_indices] + y_test = [label_array[i] for i in test_indices] + + if flatten: + X_train, y_train = flatten_X_y(X_train, y_train) + else: + X_train, y_train = average_and_drop_na(X_train, y_train) + + X_test, y_test = flatten_X_y(X_test, y_test) + + return X_train, X_test, y_train, y_test + +######################################################################################### +def plot_r2_curve(y_true, y_pred): + """ + Plots a scatter plot of true (on x axis) vs. predicted values (y axis) and displays the R-squared value on the plot + also add a diagonal reference dot line for reference + + Args: + y_true (np.ndarray): Ground truth (actual) values. + y_pred (np.ndarray): Predicted values from the model. + + """ + + r2 = r2_score(y_true, y_pred) + TRUE, PRED = y_true, y_pred + sns.set( + font="arial", + palette="colorblind", + style="whitegrid", + font_scale=1.5, + rc={"figure.figsize": (5, 5), "axes.grid": False}, + ) + sns.regplot( + x=TRUE, + y=PRED, + fit_reg=0, + marker="+", + color="black", + scatter_kws={"s": 40, "linewidths": 0.7}, + ) + plt.plot([min(TRUE), max(TRUE)], [min(TRUE), max(TRUE)], + linestyle='--', + color='blue', + linewidth=1) + plt.xlabel("Experiment ground truth ") + plt.ylabel("Model prediction") + plt.title(f'R2: {r2:.2f}', fontsize=14) + plt.xlim(min(TRUE) - 0.2, max(TRUE) + 0.5) + plt.ylim(min(PRED) - 0.2, max(PRED) + 0.5) + plt.show() + + +def plot_selected_point(y_pred, std_pred, condition, title): + """ + Plots a scatter plot of all generated point's predicted values (y_pred) vs. predicted standard deviations (std_pred), + highlighting choosen points in red by active learning based on EI condition (or UCB or PI) + + Args: + ax (matplotlib.axes.Axes): The matplotlib axis to plot on. + y_pred (np.ndarray): The predicted yield values. + std_pred (np.ndarray): The predicted standard deviation values. + condition (list or np.ndarray): The condition used to select points for highlighting (EI) + title (str): The title of the plot. + + """ + fig, ax = plt.subplots(1, 1, figsize=(5, 5)) + position = np.where(np.isin(y_pred, condition))[0] + selected_std = std_pred[position] + selected_y = y_pred[position] + + y_not = np.delete(y_pred,position) + std_not = np.delete(std_pred,position) + + ax.scatter(y_not, std_not, c='grey', label='Unselected points', alpha = 0.5) + ax.scatter(selected_y, selected_std, c='red', alpha = 0.5, label='Selected_point') + + ax.set_title(title) + ax.set_xlabel('Predicted yield') + ax.set_ylabel('Predicted std') + ax.legend(loc='upper left', prop={'size': 10}) + + plt.tight_layout() + plt.show() + + +def plot_heatmap(ax, X_new_norm, y_pred, element_list, title): + """ + Plots a heatmap of normalized data (X_new_norm), sorted by predicted values (y_pred), + with elements along the y-axis. This shows how the model understand the evolution/relationship of each component to yield + + Args: + ax (matplotlib.axes.Axes): The matplotlib axis to plot on. + X_new_norm (np.ndarray): A 2D array of normalized feature data (rows = samples, columns = features). + y_pred (np.ndarray): Predicted values used for sorting the heatmap rows. + element_list (list of str): List of element names to display on the y-axis. + title (str): The title of the plot. + + Returns: + None: The plot is drawn on the provided axis `ax`. + """ + n = len(y_pred) + sorted_indices = np.argsort(y_pred) + sorted_X = X_new_norm[sorted_indices].T + + heatmap = ax.imshow(sorted_X, aspect='auto', cmap='viridis') + + ax.set_xticks([]) + ax.set_title(f"{title}, samples = {n}", size=12) + + ax.set_yticks(np.arange(len(element_list))) + ax.set_yticklabels(element_list, fontsize=12) + + cbar = plt.colorbar(heatmap, ax=ax) + cbar.set_label('Ratio to Max Concentration', size=12) + + +def plot_each_round(y,size_list, predict = False): + """ + Plots a boxplot showing the distribution of 'y' values across different rounds, + with an option to highlight the last boxplot if it's a prediction from our model. + + Args: + y (np.ndarray or list): The yield values to plot. + size_list (list of int): A list containing the number of data in each round. + predict (bool): If True, the last boxplot will be highlighted with a different color. + + """ + cumulative_sizes = np.cumsum(size_list) + subarrays = np.split(y, cumulative_sizes) + flattened_arrays = [subarray.flatten() for subarray in subarrays] + + y_by_file = {} + for i in range(len(size_list)): + name = 'round ' + str(i) + y_by_file[name] = flattened_arrays[i] + + y_by_file = pd.DataFrame.from_dict(y_by_file, orient='index').transpose() + + boxprops = dict(linewidth=0) + medianprops = dict(linewidth=1, color='red', linestyle='dashed') + ax = sns.boxplot(y_by_file, color = 'yellow', width=0.3, boxprops=boxprops, medianprops= medianprops) + + median_values = y_by_file.median() + for i, value in enumerate(median_values): + ax.annotate(f'{value:.2f}', (i, value), textcoords="offset points", xytext=(0,3), + ha='center', fontsize=8, color='black') + + if predict: + last_box = ax.patches[-1] + + last_box.set_facecolor('silver') + + plt.ylabel('Yield') + plt.title('Yield evolution through each active learning query') + plt.show() + + +def plot_train_test(train, test, element_list): + """ + Plots histograms comparing train and test data distributions for each element + in the provided element list. Histograms for each element are displayed in a grid. + + Args: + train (np.ndarray or pd.DataFrame): The training data with elements as columns. + test (np.ndarray or pd.DataFrame): The test data with elements as columns. + element_list (list of str): List of element names (column names) to plot. + """ + test = pd.DataFrame(test, columns=element_list) + train = pd.DataFrame(train, columns=element_list) + + no_element = len(element_list) + nrows = int(np.ceil(np.sqrt(no_element))) + ncols = int(np.ceil(no_element / nrows)) + fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=(15, 8)) + + axes = axes.flatten() + + for i, column in enumerate(element_list): + hist_range = [min(train[column]), max(train[column])] + axes[i].hist(train[column], alpha=0.3, label='Previous data', bins=10) + axes[i].hist(test[column], range=hist_range, alpha=1, label='New data', bins=10) + axes[i].set_title(column) + axes[i].legend() + + for j in range(i + 1, len(axes)): + fig.delaxes(axes[j]) diff --git a/icfree/learner/new_exp/plate3_ei50.csv b/icfree/learner/new_exp/plate3_ei50.csv new file mode 100644 index 0000000..52e0974 --- /dev/null +++ b/icfree/learner/new_exp/plate3_ei50.csv @@ -0,0 +1,51 @@ +Mg-glutamate,K-glutamate,Amino acid,Spermidine,Creatine Phosphate,NTP,GFP11_Col-E1,GFP1-10,PEG-8000 +60.0,840.0,420.0,80.0,180.0,100.0,520.0,1240.0,940.0 +60.0,940.0,860.0,120.0,180.0,120.0,540.0,1040.0,760.0 +60.0,660.0,840.0,140.0,280.0,140.0,680.0,1180.0,1020.0 +40.0,760.0,1020.0,140.0,20.0,140.0,620.0,1120.0,600.0 +80.0,720.0,760.0,140.0,60.0,140.0,720.0,1140.0,1260.0 +80.0,860.0,280.0,60.0,100.0,120.0,360.0,1240.0,680.0 +60.0,840.0,260.0,60.0,80.0,140.0,520.0,1000.0,1180.0 +80.0,820.0,260.0,140.0,140.0,140.0,640.0,1120.0,760.0 +80.0,660.0,980.0,60.0,40.0,120.0,700.0,1220.0,720.0 +80.0,800.0,860.0,100.0,260.0,120.0,820.0,1060.0,440.0 +60.0,820.0,700.0,40.0,80.0,140.0,680.0,1140.0,1040.0 +60.0,980.0,60.0,60.0,20.0,120.0,840.0,1060.0,780.0 +60.0,680.0,360.0,140.0,200.0,120.0,580.0,1220.0,540.0 +60.0,860.0,580.0,140.0,100.0,120.0,560.0,1200.0,140.0 +80.0,980.0,480.0,80.0,280.0,120.0,320.0,1180.0,1160.0 +80.0,940.0,660.0,20.0,120.0,120.0,360.0,1240.0,860.0 +80.0,480.0,1000.0,100.0,160.0,140.0,620.0,940.0,1100.0 +80.0,900.0,600.0,120.0,100.0,120.0,360.0,900.0,960.0 +80.0,700.0,1100.0,140.0,360.0,140.0,680.0,980.0,1180.0 +60.0,860.0,320.0,80.0,180.0,120.0,240.0,1220.0,700.0 +80.0,780.0,600.0,100.0,260.0,100.0,500.0,840.0,660.0 +80.0,620.0,520.0,40.0,140.0,140.0,540.0,860.0,1100.0 +40.0,580.0,1000.0,140.0,80.0,140.0,820.0,1220.0,20.0 +80.0,820.0,480.0,140.0,20.0,80.0,620.0,980.0,900.0 +80.0,740.0,980.0,140.0,260.0,100.0,680.0,800.0,1280.0 +80.0,400.0,800.0,60.0,140.0,100.0,840.0,1240.0,980.0 +40.0,380.0,900.0,100.0,140.0,140.0,660.0,1120.0,680.0 +40.0,560.0,840.0,100.0,300.0,120.0,840.0,1000.0,1320.0 +60.0,860.0,840.0,80.0,140.0,80.0,400.0,1020.0,780.0 +80.0,960.0,240.0,20.0,60.0,120.0,60.0,980.0,860.0 +40.0,780.0,240.0,40.0,300.0,140.0,280.0,840.0,840.0 +40.0,840.0,380.0,60.0,340.0,120.0,700.0,860.0,1320.0 +60.0,840.0,580.0,140.0,380.0,120.0,460.0,980.0,1180.0 +40.0,520.0,940.0,140.0,20.0,100.0,800.0,1160.0,260.0 +40.0,940.0,380.0,80.0,60.0,140.0,20.0,1140.0,1160.0 +80.0,720.0,700.0,120.0,320.0,140.0,280.0,1000.0,800.0 +40.0,760.0,300.0,100.0,80.0,140.0,620.0,800.0,1120.0 +80.0,700.0,440.0,120.0,320.0,140.0,680.0,640.0,1120.0 +40.0,740.0,500.0,80.0,60.0,140.0,720.0,780.0,440.0 +80.0,800.0,400.0,100.0,140.0,120.0,860.0,660.0,980.0 +20.0,960.0,260.0,20.0,140.0,100.0,180.0,1000.0,580.0 +80.0,480.0,540.0,100.0,440.0,140.0,380.0,1100.0,980.0 +20.0,740.0,160.0,60.0,300.0,120.0,360.0,1040.0,1200.0 +60.0,980.0,400.0,60.0,400.0,80.0,700.0,1080.0,980.0 +60.0,620.0,300.0,60.0,420.0,140.0,460.0,980.0,940.0 +60.0,880.0,1000.0,140.0,180.0,80.0,860.0,840.0,800.0 +60.0,740.0,440.0,120.0,120.0,120.0,660.0,760.0,500.0 +60.0,920.0,120.0,20.0,180.0,120.0,280.0,620.0,620.0 +60.0,940.0,200.0,60.0,180.0,80.0,800.0,1100.0,500.0 +20.0,800.0,320.0,100.0,240.0,140.0,400.0,820.0,1080.0 diff --git a/icfree/learner/param.tsv b/icfree/learner/param.tsv new file mode 100644 index 0000000..1554161 --- /dev/null +++ b/icfree/learner/param.tsv @@ -0,0 +1,10 @@ +Component maxValue +Mg-glutamate 65.6 +K-glutamate 962.5 +Amino acid 1093.8 +Spermidine 131.3 +Creatine Phosphate 937.5 +NTP 126.2 +GFP11_Col-E1 858 +GFP1-10 1237.3 +PEG-8000 1312.5 \ No newline at end of file diff --git a/tests/data/learner/calibrator/input/plate1.csv b/tests/data/learner/calibrator/input/plate1.csv new file mode 100644 index 0000000..f258d70 --- /dev/null +++ b/tests/data/learner/calibrator/input/plate1.csv @@ -0,0 +1,58 @@ +Mg-glutamate,K-glutamate,Spermidine,3-PGA,NTP,HEPES,Amino acid,DNA 1,DNA 2,PEG-8000,Fluorescence Value 1,Fluorescence Value 2,Fluorescence Value 3,Fluorescence Value 4,Fluorescence Value 5,Fluorescence Value 6,Fluorescence Average +105.04000000000002,350.0,52.52000000000001,168.78,100.96,262.5,1094.0,239.478,1485.0,524.8000000000001,36140,6902,15845,54245,43873,55311,35386.0 +131.3,350.0,78.78,225.04,75.72,262.5,875.2,239.478,1232.55,524.8000000000001,8700,37686,23365,40813,49240,12430,28705.666666666668 +52.52000000000001,210.0,131.3,112.52,50.48,262.5,1094.0,239.478,1485.0,524.8000000000001,3278,12738,3958,13847,7719,6531,8011.833333333333 +105.04000000000002,280.0,105.04000000000002,225.04,50.48,262.5,1094.0,960.78,1485.0,524.8000000000001,20109,29187,13350,39574,20023,21574,23969.5 +105.04000000000002,210.0,105.04000000000002,281.3,126.2,262.5,1094.0,717.0,994.95,262.40000000000003,22265,3832,7063,22677,14288,19902,15004.5 +52.52000000000001,350.0,131.3,168.78,50.48,262.5,875.2,473.22,1232.55,262.40000000000003,22981,36101,34604,17483,13593,13016,22963.0 +105.04000000000002,350.0,105.04000000000002,168.78,75.72,262.5,1094.0,717.0,994.95,0.0,22786,3998,12503,8663,27532,15902,15230.666666666666 +52.52000000000001,280.0,105.04000000000002,225.04,100.96,262.5,875.2,473.22,1232.55,1049.6,27675,3701,47245,9018,14621,14842,19517.0 +26.260000000000005,210.0,78.78,281.3,100.96,262.5,656.4,717.0,1485.0,262.40000000000003,30810,13668,59960,14771,30380,33003,30432.0 +78.78,140.0,131.3,225.04,126.2,262.5,1094.0,960.78,994.95,262.40000000000003,16034,2093,9285,3575,2330,2766,6013.833333333333 +78.78,280.0,105.04000000000002,112.52,100.96,262.5,875.2,473.22,1232.55,787.1999999999999,22414,5276,3043,8105,4708,11716,9210.333333333334 +131.3,350.0,0.0,112.52,25.24,262.5,1094.0,1434.0,1485.0,787.1999999999999,5780,5314,3669,6026,2990,3937,4619.333333333333 +78.78,70.0,131.3,225.04,75.72,262.5,875.2,717.0,1232.55,524.8000000000001,9022,4509,4967,5066,10604,11422,7598.333333333333 +78.78,280.0,78.78,281.3,75.72,262.5,1094.0,717.0,994.95,787.1999999999999,15814,17225,5057,5453,3721,2150,8236.666666666666 +26.260000000000005,280.0,105.04000000000002,225.04,100.96,262.5,656.4,239.478,994.95,787.1999999999999,21552,11688,5880,4468,46172,32927,20447.833333333332 +131.3,210.0,0.0,281.3,0.0,262.5,875.2,473.22,1485.0,524.8000000000001,2652,5513,2182,7323,2265,2872,3801.1666666666665 +105.04000000000002,70.0,52.52000000000001,281.3,100.96,262.5,656.4,717.0,1485.0,524.8000000000001,11196,7737,5212,7669,10221,29061,11849.333333333334 +78.78,140.0,78.78,281.3,126.2,262.5,218.8,473.22,1485.0,262.40000000000003,18125,20552,12251,8258,16269,21473,16154.666666666666 +131.3,210.0,0.0,281.3,50.48,262.5,875.2,239.478,994.95,524.8000000000001,13258,8982,9923,3533,15310,1627,8772.166666666666 +78.78,0.0,131.3,281.3,126.2,262.5,656.4,473.22,1485.0,524.8000000000001,5226,3905,4105,3319,3831,4202,4098.0 +78.78,350.0,131.3,168.78,50.48,262.5,656.4,960.78,1485.0,524.8000000000001,15313,25078,4725,35079,7495,12072,16627.0 +105.04000000000002,350.0,0.0,281.3,126.2,262.5,1094.0,239.478,1232.55,787.1999999999999,21108,54417,9911,15819,34667,11366,24548.0 +52.52000000000001,350.0,78.78,225.04,0.0,262.5,875.2,239.478,1485.0,787.1999999999999,3385,2871,2493,2763,8311,2768,3765.1666666666665 +105.04000000000002,280.0,78.78,225.04,25.24,262.5,1094.0,717.0,1232.55,787.1999999999999,37022,5132,6616,11364,6381,38422,17489.5 +52.52000000000001,350.0,0.0,112.52,50.48,262.5,656.4,473.22,1485.0,0.0,23438,5435,15227,14312,13139,24264,15969.166666666666 +105.04000000000002,280.0,0.0,225.04,100.96,262.5,1094.0,1434.0,1485.0,1049.6,17481,5290,7182,7721,6107,25667,11574.666666666666 +105.04000000000002,140.0,105.04000000000002,281.3,100.96,262.5,875.2,717.0,1232.55,1049.6,25935,10397,6792,9857,2981,36945,15484.5 +131.3,0.0,105.04000000000002,225.04,126.2,262.5,875.2,717.0,1485.0,787.1999999999999,6322,4588,3837,4466,4105,4356,4612.333333333333 +0.0,140.0,131.3,168.78,50.48,262.5,875.2,473.22,1485.0,524.8000000000001,27304,8210,14500,14879,8220,34587,17950.0 +26.260000000000005,140.0,131.3,112.52,50.48,262.5,1094.0,473.22,1232.55,0.0,8048,4067,6508,5451,5387,16283,7624.0 +131.3,140.0,131.3,112.52,126.2,262.5,1094.0,239.478,994.95,1049.6,3780,5133,2149,4733,2940,2512,3541.1666666666665 +105.04000000000002,350.0,26.260000000000005,56.260000000000005,100.96,262.5,656.4,960.78,1485.0,262.40000000000003,23554,5453,3644,6347,6270,8051,8886.5 +131.3,350.0,0.0,56.260000000000005,100.96,262.5,437.6,960.78,1485.0,787.1999999999999,5965,4330,4628,5867,5592,3110,4915.333333333333 +26.260000000000005,280.0,131.3,168.78,75.72,262.5,875.2,1190.22,1485.0,787.1999999999999,9646,18936,4724,5587,6454,4690,8339.5 +131.3,350.0,131.3,168.78,75.72,262.5,1094.0,717.0,742.5,787.1999999999999,7498,3886,5149,4449,3192,7388,5260.333333333333 +78.78,350.0,131.3,56.260000000000005,100.96,262.5,437.6,473.22,1485.0,524.8000000000001,5456,9885,5500,10123,6592,6123,7279.833333333333 +78.78,280.0,26.260000000000005,281.3,75.72,262.5,656.4,717.0,1232.55,787.1999999999999,17492,52467,2590,13196,4949,5596,16048.333333333334 +131.3,350.0,52.52000000000001,0.0,75.72,262.5,875.2,473.22,1232.55,0.0,2873,3674,3389,3191,3883,3504,3419.0 +131.3,210.0,0.0,225.04,100.96,262.5,1094.0,960.78,1232.55,524.8000000000001,5196,47273,5795,10877,4668,6685,13415.666666666666 +105.04000000000002,0.0,78.78,281.3,50.48,262.5,875.2,239.478,1232.55,524.8000000000001,5160,4145,3482,3905,4164,4761,4269.5 +0.0,350.0,0.0,225.04,75.72,262.5,875.2,960.78,1485.0,1049.6,9321,8132,9793,9449,7733,10254,9113.666666666666 +78.78,350.0,131.3,168.78,126.2,262.5,1094.0,717.0,994.95,1049.6,3344,5979,13763,5181,3895,3792,5992.333333333333 +131.3,210.0,131.3,56.260000000000005,50.48,262.5,1094.0,960.78,1232.55,262.40000000000003,2510,2149,2456,2261,2753,2553,2447.0 +52.52000000000001,280.0,52.52000000000001,225.04,126.2,262.5,875.2,1434.0,1485.0,787.1999999999999,5881,5767,11856,12278,11019,10059,9476.666666666666 +105.04000000000002,280.0,52.52000000000001,112.52,75.72,262.5,437.6,239.478,1485.0,1049.6,9019,4699,7379,10451,7653,6517,7619.666666666667 +131.3,0.0,52.52000000000001,225.04,50.48,262.5,875.2,473.22,1485.0,0.0,4841,5252,4397,5488,6103,4730,5135.166666666667 +105.04000000000002,280.0,131.3,112.52,50.48,262.5,1094.0,473.22,490.05,0.0,3292,9790,4064,3639,4957,3000,4790.333333333333 +131.3,140.0,78.78,168.78,100.96,262.5,437.6,717.0,1232.55,0.0,32530,16336,9639,7253,9296,4295,13224.833333333334 +26.260000000000005,210.0,78.78,225.04,100.96,262.5,1094.0,473.22,742.5,524.8000000000001,5806,5606,6277,5625,3814,5031,5359.833333333333 +131.3,210.0,105.04000000000002,225.04,50.48,262.5,875.2,1190.22,994.95,0.0,17987,10872,5632,20528,5022,17835,12979.333333333334 +105.0,280.0,105.0,225.0,100.0,262.5,875.0,0.0,0.0,1050.0,2035,2121,2035,2287,2022,3024,2254.0 +105.0,280.0,105.0,225.0,100.0,262.5,875.0,1435.0,1485.0,1050.0,8456,10587,6288,3708,5467,7546,7008.666666666667 +130.0,140.0,130.0,280.0,100.0,262.5,1095.0,240.0,490.0,262.5,2769,7765,26971,15274,2130,5547,10076.0 +25.0,140.0,52.5,55.0,100.0,262.5,1095.0,472.5,1232.5,0.0,2079,6661,7051,4644,6330,7247,5668.666666666667 +130.0,350.0,0.0,112.5,50.0,262.5,655.0,960.0,1485.0,1050.0,5982,6252,6378,4912,7080,4929,5922.166666666667 +52.5,210.0,130.0,225.0,75.0,262.5,1095.0,240.0,1232.5,525.0,3394,10041,11931,23802,17023,10483,12779.0 +25.0,280.0,52.5,225.0,75.0,262.5,875.0,472.5,1232.5,262.5,4735,7146,11174,14050,17451,10527,10847.166666666666 diff --git a/tests/data/learner/calibrator/input/plate1.xlsx b/tests/data/learner/calibrator/input/plate1.xlsx new file mode 100644 index 0000000..ec4ffa8 Binary files /dev/null and b/tests/data/learner/calibrator/input/plate1.xlsx differ diff --git a/tests/data/learner/calibrator/input/plate1_yields.xlsx b/tests/data/learner/calibrator/input/plate1_yields.xlsx new file mode 100644 index 0000000..0bc00ad Binary files /dev/null and b/tests/data/learner/calibrator/input/plate1_yields.xlsx differ diff --git a/tests/data/learner/calibrator/input/plate2-yields.xlsx b/tests/data/learner/calibrator/input/plate2-yields.xlsx new file mode 100644 index 0000000..93b078c Binary files /dev/null and b/tests/data/learner/calibrator/input/plate2-yields.xlsx differ diff --git a/tests/data/learner/calibrator/input/plate2.xlsx b/tests/data/learner/calibrator/input/plate2.xlsx new file mode 100644 index 0000000..8c937d3 Binary files /dev/null and b/tests/data/learner/calibrator/input/plate2.xlsx differ diff --git a/tests/data/learner/calibrator/input/plate3.xlsx b/tests/data/learner/calibrator/input/plate3.xlsx new file mode 100644 index 0000000..ba6bb4b Binary files /dev/null and b/tests/data/learner/calibrator/input/plate3.xlsx differ diff --git a/tests/data/learner/calibrator/input/~$plate3.xlsx b/tests/data/learner/calibrator/input/~$plate3.xlsx new file mode 100644 index 0000000..5a93205 Binary files /dev/null and b/tests/data/learner/calibrator/input/~$plate3.xlsx differ diff --git a/tests/data/learner/calibrator/output/plate2-calibrated.csv b/tests/data/learner/calibrator/output/plate2-calibrated.csv new file mode 100644 index 0000000..0bb0570 --- /dev/null +++ b/tests/data/learner/calibrator/output/plate2-calibrated.csv @@ -0,0 +1,1000 @@ +Well;Mg-glutamate;K-glutamate;Spermidine;3-PGA;NTP;HEPES;Amino acid;DNA 1;DNA 2;PEG-8000;Fluorescence value1;Fluorescence value2;Fluorescence value3;Fluorescence value4;Fluorescence value5;;Yield 1 ;Yield 2;Yield 3;Yield 4;Yield 5;Average;Calibrated Yield 1 ;Calibrated Yield 2;Calibrated Yield 3;Calibrated Yield 4;Calibrated Yield 5;;;;;;;;;;; +A1;131,3;350;78,78;281,3;126,2;262,5;656,4;473,22;1485;524,8;23466;38819;26556;29480;32333;;3,156835254;5,42265972;3,612863236;4,044392627;4,465443705;4,140438908;5,613615256;9,689380305;6,433918389;7,210153457;7,967540136;;;;;;;;;;; +B1;131,3;350;52,52;281,3;126,2;262,5;875,2;473,22;1232,55;787,2;29210;39639;30443;11538;29979;;4,004545522;5,543676855;4,186513969;1,396478697;4,11803598;3,849850204;7,138476484;9,907065926;7,465801327;2,447085879;7,342623122;;;;;;;;;;; +C1;131,3;280;78,78;225,04;126,2;262,5;437,6;239,478;1485;262,4;20716;24132;18945;18214;20140;;2,750985109;3,25512478;2,489617615;2,381735268;2,665977951;2,708688145;4,883572014;5,790418455;4,413424167;4,219365399;4,730661139;;;;;;;;;;; +D1;52,52;280;52,52;281,3;100,96;262,5;875,2;473,22;1485;787,2;22693;33738;22474;22257;16403;;3,042754468;4,672796234;3,010434038;2,978408772;2,114464499;3,163771602;5,408406737;8,340525865;5,350268748;5,2926617;3,738598741;;;;;;;;;;; +E1;26,26;210;131,3;281,3;126,2;262,5;437,6;239,478;1485;262,4;37003;26221;19053;21768;13822;;5,154651043;3,563423309;2,505556457;2,906241237;1,73355569;3,172685547;9,207286296;6,344985848;4,442094956;5,162846738;3,053419975;;;;;;;;;;; +F1;26,26;280;105,04;168,78;100,96;262,5;218,8;473,22;1485;0;17608;7051;12803;15009;12124;;2,292300654;0,734278841;1,583169763;1,908735371;1,482961673;1,60028926;4,058490416;1,25592078;2,78290577;3,368533185;2,602651457;;;;;;;;;;; +G1;78,78;280;52,52;168,78;126,2;262,5;1094;717;1485;787,2;13299;15254;10320;10962;11092;;1,656370371;1,944892929;1,216723978;1,311471539;1,330657182;1,4920232;2,914579024;3,433573401;2,123743091;2,294175004;2,328686139;;;;;;;;;;; +H1;0;280;131,3;281,3;126,2;262,5;218,8;473,22;994,95;262,4;15670;8328;8611;3949;2692;;2,006286988;0,922740891;0,96450656;0,276479877;0,090969465;0,852196756;3,544009033;1,594926314;1,6700544;0,432432003;0,098735874;;;;;;;;;;; +I1;131,3;210;105,04;225,04;100,96;262,5;218,8;239,478;1485;262,4;29298;18862;20092;17731;18972;;4,017532726;2,47736832;2,658894021;2,310453224;2,493602326;2,791570124;7,161837868;4,391390134;4,717918566;4,091143259;4,420591864;;;;;;;;;;; +J1;26,26;350;105,04;281,3;100,96;262,5;437,6;960,78;1232,55;0;27264;13765;8152;7279;4822;;3,717351201;1,725143523;0,896766481;0,767927508;0,405318851;1,502501513;6,62187134;3,03828817;1,548203546;1,316448001;0,664187549;;;;;;;;;;; +K1;78,78;350;131,3;281,3;50,48;262,5;656,4;239,478;1232,55;1049,6;35588;10892;35569;37182;15561;;4,945822695;1,301140808;4,94301864;5,181068198;1,990200564;3,672250181;8,831645864;2,275592085;8,826601929;9,254805474;3,515072774;;;;;;;;;;; +L1;52,52;350;0;281,3;75,72;262,5;1094;473,22;1232,55;0;45251;5526;11401;3716;3696;;6,371906315;0,509216488;1,37625998;0,242093301;0,239141664;1,74772355;11,39688508;0,851078618;2,410716452;0,37057743;0,365268025;;;;;;;;;;; +M1;78,78;280;52,52;112,52;126,2;262,5;875,2;239,478;1232,55;524,8;21170;8207;12713;10317;7583;;2,817987278;0,904883484;1,569887395;1,216281232;0,812792397;1,464366357;5,004095516;1,562804411;2,759013446;2,12294668;1,397150963;;;;;;;;;;; +N1;26,26;350;105,04;281,3;50,48;262,5;218,8;717;1485;0;31844;11146;13644;7439;14240;;4,39327617;1,338626603;1,707286117;0,791540607;1,795244912;2,005194882;7,837725175;2,343021534;3,006166267;1,358923244;3,164386548;;;;;;;;;;; +O1;78,78;350;26,26;281,3;126,2;262,5;0;239,478;1232,55;787,2;11846;3165;7350;3163;7779;;1,441933913;0,16077569;0,778405821;0,160480527;0,841718443;0,676662879;2,528850722;0,224303312;1,33529639;0,223772371;1,449183136;;;;;;;;;;; +P1;131,3;350;78,78;225,04;100,96;262,5;1094;717;742,5;0;27014;8594;17411;4594;26943;;3,680455733;0,961997668;2,263227025;0,371670184;3,66997742;2,189465606;6,555503772;1,665541406;4,006192773;0,603660327;6,536655383;;;;;;;;;;; +A2;131,3;210;26,26;168,78;50,48;262,5;1094;473,22;1485;0;5662;10015;14800;8518;14720;;0,529287622;1,171711507;1,87789076;0,950781446;1,86608421;1,279151109;0,887182575;2,042774659;3,313049899;1,645365665;3,291812277;;;;;;;;;;; +B2;105,04;210;131,3;281,3;75,72;262,5;218,8;239,478;1232,55;787,2;29026;31062;30052;26439;13315;;3,977390457;4,277867147;4,128809457;3,595596157;1,658731681;3,52767898;7,089629955;7,630127424;7,362002451;6,402858367;2,918826549;;;;;;;;;;; +C2;52,52;140;105,04;168,78;100,96;262,5;218,8;239,478;1485;0;21741;17466;16295;14871;15867;;2,902256527;2,271344028;2,098525657;1,888369073;2,035360616;2,23917118;5,15567904;4,020793638;3,709927952;3,331898288;3,596306677;;;;;;;;;;; +D2;105,04;350;0;112,52;126,2;262,5;437,6;473,22;1485;262,4;11860;7439;5347;5779;6388;;1,444000059;0,791540607;0,482799333;0,546554701;0,636432061;0,780265352;2,532567306;1,358923244;0,80355944;0,918242597;1,079913991;;;;;;;;;;; +E2;131,3;350;0;112,52;126,2;262,5;875,2;239,478;742,5;262,4;14019;4996;9549;4247;4580;;1,762629319;0,430998096;1,102938355;0,320459275;0,369604038;0,797325816;3,105717618;0,710379375;1,919065513;0,511542143;0,599943743;;;;;;;;;;; +F2;52,52;280;52,52;281,3;126,2;262,5;0;239,478;994,95;262,4;5383;3249;2979;4886;2608;;0,48811228;0,173172567;0,133325462;0,41476409;0,078572588;0,257589398;0,81311637;0,246602814;0,174925842;0,681177646;0,076436372;;;;;;;;;;; +G2;105,04;350;105,04;225,04;126,2;262,5;656,4;239,478;994,95;1049,6;34223;8463;26587;10533;8908;;4,744373441;0,942664443;3,617438274;1,248158916;1,008338376;2,31219469;8,469278946;1,6307648;6,442147967;2,180288258;1,74889907;;;;;;;;;;; +H2;0;280;78,78;281,3;126,2;262,5;437,6;1434;1485;524,8;10387;11125;2908;9525;2844;;1,226611963;1,335527384;0,122847149;1,09939639;0,11340191;0,779556959;2,141529599;2,337446658;0,156077452;1,912694227;0,139087355;;;;;;;;;;; +I2;0;350;105,04;281,3;126,2;262,5;218,8;1190,22;1232,55;1049,6;9023;5813;9081;3742;5270;;1,025310291;0,551572485;1,033870039;0,24593043;0,471435529;0,665623755;1,779428151;0,927268586;1,794825427;0,377479657;0,783118229;;;;;;;;;;; +J2;131,3;280;131,3;281,3;100,96;262,5;875,2;1190,22;994,95;0;47181;6743;19685;18473;4972;;6,656739326;0,688823625;2,5988282;2,419958972;0,427456131;2,558361251;11,9092427;1,174155936;4,609872166;4,288122199;0,704008089;;;;;;;;;;; +K2;131,3;140;52,52;225,04;126,2;262,5;875,2;239,478;994,95;524,8;10639;7721;16774;14418;5403;;1,263802594;0,833158695;2,169217373;1,821514485;0,491063918;1,315751413;2,208428107;1,43378586;3,837088211;3,211640256;0,818425775;;;;;;;;;;; +L2;78,78;210;52,52;225,04;75,72;262,5;656,4;239,478;1485;1049,6;29231;15947;15487;13972;17460;;4,007644741;2,047167166;1,979279505;1,755692971;2,270458537;2,412048584;7,14405136;3,617544298;3,495427974;3,093240516;4,019200816;;;;;;;;;;; +M2;105,04;280;131,3;281,3;126,2;262,5;1094;1434;1232,55;0;9102;11822;19416;12977;21625;;1,036969259;1,438391948;2,559128677;1,608849009;2,88513703;1,905695184;1,800400303;2,522479436;4,538460664;2,829097597;5,124884489;;;;;;;;;;; +N2;78,78;140;105,04;281,3;126,2;262,5;875,2;239,478;1485;1312;31876;16844;28687;19286;35918;;4,39799879;2,179548104;3,927360203;2,539943033;4,994524713;3,607874969;7,846220223;3,85567113;6,999635533;4,503949528;8,919251053;;;;;;;;;;; +O2;131,3;280;105,04;225,04;126,2;262,5;0;717;1232,55;262,4;5573;6775;5716;3475;7546;;0,516152836;0,693546245;0,537257043;0,20652607;0,807331867;0,552162812;0,863555721;1,182650985;0,90151797;0,306599095;1,387328563;;;;;;;;;;; +P2;26,26;210;52,52;281,3;75,72;262,5;875,2;239,478;1485;1312;36312;22874;16165;25485;36624;;5,05267197;3,069466787;2,079340014;3,454803052;5,098717514;3,750999867;9,023846339;5,456456856;3,675416817;6,14959973;9,106673063;;;;;;;;;;; +A3;78,78;210;0;225,04;75,72;262,5;875,2;239,478;1232,55;262,4;9125;10434;13713;8968;5512;;1,040363642;1,233548311;1,717469266;1,017193288;0,507150342;1,10314497;1,806506119;2,154006702;3,024483716;1,764827286;0,847362035;;;;;;;;;;; +B3;0;280;52,52;225,04;75,72;262,5;875,2;239,478;1485;524,8;37689;19642;23109;22024;6046;;5,255892206;2,592482179;3,104148526;2,944022196;0,585959061;2,896500834;9,389398901;4,598456944;5,518842369;5,230807127;0,989123159;;;;;;;;;;; +C3;105,04;280;26,26;112,52;126,2;262,5;218,8;239,478;1232,55;262,4;9985;10644;10005;9357;9685;;1,167284051;1,264540504;1,170235688;1,074602636;1,12300949;1,159934474;2,034810551;2,209755458;2,040119956;1,868095221;1,95516947;;;;;;;;;;; +D3;0;140;105,04;168,78;75,72;262,5;218,8;239,478;1232,55;0;20996;20758;13904;14643;13687;;2,792308033;2,757183548;1,745657403;1,854720406;1,713632137;2,172700305;4,95790369;4,894721765;3,075188537;3,271371067;3,017581489;;;;;;;;;;; +E3;26,26;350;105,04;281,3;126,2;262,5;656,4;1190,22;994,95;262,4;13167;17284;2148;11130;9407;;1,636889564;2,244484128;0,010684927;1,336265293;1,081981729;1,262061128;2,879536949;3,972478049;-0,045679952;2,338774009;1,881368735;;;;;;;;;;; +F3;52,52;210;131,3;168,78;126,2;262,5;875,2;473,22;1485;787,2;21324;15260;12931;15062;16419;;2,840714887;1,945778421;1,602060243;1,91655721;2,116825809;2,084387314;5,044977938;3,435166223;2,816885965;3,38260311;3,742846265;;;;;;;;;;; +G3;78,78;350;0;281,3;126,2;262,5;218,8;239,478;490,05;0;2383;2222;2249;2203;2427;;0,045366667;0,021605986;0,025590696;0,01880193;0,051860269;0,03264511;0,016705561;-0,026035153;-0,018867455;-0,031079088;0,028386253;;;;;;;;;;; +H3;105,04;210;52,52;281,3;126,2;262,5;0;960,78;1485;0;3662;3242;2733;2919;6292;;0,23412388;0,172139494;0,097020322;0,12447055;0,622264201;0,25000369;0,356242036;0,244744522;0,109620155;0,158997625;1,054428845;;;;;;;;;;; +I3;52,52;210;26,26;281,3;75,72;262,5;1094;239,478;1232,55;787,2;18493;24519;16613;11931;16898;;2,42291061;3,312238965;2,145456692;1,454478372;2,187517525;2,304520433;4,293431605;5,893155449;3,794347498;2,551415695;3,870006525;;;;;;;;;;; +J3;0;0;0;281,3;126,2;262,5;0;1190,22;1232,55;1312;6029;4741;4809;4640;5275;;0,583450169;0,393364719;0,403400286;0,37845895;0,472173438;0,446169513;0,984610164;0,642684457;0,660736435;0,615871959;0,784445581;;;;;;;;;;; +K3;26,26;140;131,3;281,3;126,2;262,5;0;717;994,95;524,8;4920;4356;4815;3003;3689;;0,419781874;0,336545699;0,404285778;0,136867427;0,238108591;0,307117874;0,690203635;0,540478403;0,662329257;0,181297128;0,363409733;;;;;;;;;;; +L3;0;280;131,3;225,04;50,48;262,5;437,6;1434;1485;0;10032;9329;9840;6646;2245;;1,174220399;1,070470343;1,14588468;0,674508183;0,025000369;0,818016795;2,047287653;1,860662054;1,996317362;1,14840532;-0,019929336;;;;;;;;;;; +M3;0;70;78,78;281,3;100,96;262,5;656,4;239,478;1485;1049,6;10316;5199;8523;6618;9069;;1,21613365;0,460957216;0,951519355;0,670375891;1,032099057;0,866217034;2,12268121;0,76426984;1,646693016;1,140972153;1,791639784;;;;;;;;;;; +N3;26,26;210;52,52;225,04;126,2;262,5;656,4;960,78;1232,55;262,4;10333;3446;6196;3064;6233;;1,218642542;0,202246196;0,608096341;0,145869921;0,613556871;0,557682374;2,127194204;0,298900458;1,028943699;0,197490815;1,038766099;;;;;;;;;;; +O3;0;210;105,04;168,78;75,72;262,5;218,8;717;1485;1312;10045;10741;8935;9429;10356;;1,176138963;1,278855945;1,012323086;1,085228531;1,222036925;1,15491669;2,050738767;2,235506074;1,756066768;1,887209081;2,133300021;;;;;;;;;;; +P3;26,26;140;105,04;281,3;50,48;262,5;656,4;239,478;1232,55;524,8;17724;20570;17188;10862;29322;;2,309420151;2,729438156;2,230316268;1,296713352;4,021074691;2,517392524;4,089284967;4,844813355;3,946992903;2,267627977;7,168209155;;;;;;;;;;; +A4;52,52;210;0;225,04;126,2;262,5;1094;960,78;1485;1312;11496;7977;8897;5788;9810;;1,390280258;0,870939654;1,006714975;0,547882938;1,141457223;0,99145501;2,435936128;1,501746249;1,745978897;0,920631829;1,988353253;;;;;;;;;;; +B4;78,78;210;78,78;225,04;100,96;262,5;218,8;1190,22;1485;262,4;7397;4205;4504;3105;5032;;0,785342169;0,314260836;0,358387816;0,151920778;0,436311044;0,409244528;1,347773493;0,500392392;0,579768003;0,208375096;0,719936305;;;;;;;;;;; +C4;105,04;140;105,04;281,3;25,24;262,5;218,8;239,478;1232,55;262,4;24222;11713;18240;15414;15401;;3,268407149;1,422305524;2,385572396;1,968506029;1,966587464;2,202275712;5,814310779;2,493543177;4,226267626;3,476048644;3,472597531;;;;;;;;;;; +D4;105,04;210;26,26;0;126,2;262,5;656,4;239,478;1485;524,8;4719;3921;4084;4205;4402;;0,390117918;0,272347585;0,29640343;0,314260836;0,343334465;0,323292847;0,636844111;0,424998836;0,46827049;0,500392392;0,552690035;;;;;;;;;;; +E4;52,52;350;131,3;225,04;50,48;262,5;875,2;473,22;742,5;524,8;17237;14975;6879;16923;16600;;2,23754778;1,903717587;0,708894759;2,191207072;2,143538128;1,836981065;3,960000946;3,359507196;1,210259893;3,876643281;3,790896384;;;;;;;;;;; +F4;26,26;350;105,04;281,3;100,96;262,5;437,6;960,78;1232,55;0;14152;16296;4537;11687;6783;;1,782257707;2,098673239;0,363258017;1,418468395;0,6947269;1,271476852;3,141025164;3,710193422;0,588528522;2,48664095;1,184774747;;;;;;;;;;; +G4;131,3;350;78,78;225,04;100,96;262,5;1094;717;742,5;0;23633;13156;6753;13909;5802;;3,181481427;1,635266164;0,690299444;1,746395313;0,549949084;1,560678286;5,657948791;2,876616776;1,176810639;3,076515889;0,924348413;;;;;;;;;;; +H4;52,52;280;52,52;281,3;100,96;262,5;875,2;473,22;1485;787,2;35829;27790;15073;9463;22851;;4,981389926;3,794979265;1,918180611;1,090246314;3,066072404;2,970173704;8,895624199;6,761508701;3,385523283;1,89623507;5,45035104;;;;;;;;;;; +I4;105,04;70;105,04;281,3;0;262,5;437,6;239,478;1485;0;6382;6386;5098;6140;7687;;0,635546569;0,636136897;0,446051447;0,599831757;0,828140911;0,629141516;1,078321169;1,07938305;0,737457343;1,014077364;1,424759871;;;;;;;;;;; +J4;105,04;140;0;56,26;126,2;262,5;218,8;473,22;1485;0;5263;4873;4682;5656;5619;;0,470402456;0,412845526;0,384657389;0,528402131;0,522941602;0,463849821;0,781259937;0,677726532;0,627021711;0,885589753;0,875767353;;;;;;;;;;; +K4;131,3;280;131,3;281,3;100,96;262,5;875,2;1190,22;994,95;0;25226;12011;11367;15445;11179;;3,416579347;1,466284922;1,371242197;1,973081067;1,343496805;1,914136867;6,08084293;2,572653317;2,401690463;3,484278223;2,351782053;;;;;;;;;;; +L4;26,26;280;105,04;168,78;100,96;262,5;218,8;473,22;1485;0;15851;12079;13598;11573;13995;;2,032999306;1,476320489;1,700497351;1,401644062;1,759087354;1,674109712;3,592059152;2,590705295;2,993954635;2,456377339;3,099346332;;;;;;;;;;; +M4;105;280;105;225;100;262,5;875;0;0;1050;2154;1842;1972;1834;2576;;0,011570419;-0,034475125;-0,015289482;-0,03565578;0,073849968;0;-0,044087131;-0,126913855;-0,09240272;-0,129037617;0,067941323;;;;;;;;;;; +N4;105;280;105;225;100;262,5;875;1435;1485;1050;;8320;7586;9965;9535;;-0,306320932;0,921560236;0,813235142;1,164332413;1,100872209;0,738735814;-0,615910092;1,592802552;1,397947374;2,029501145;1,915348929;;;;;;;;;;; +O4;105,04;350;52,52;168,78;100,96;262,5;1094;239,478;1485;524,8;33955;18673;24957;18835;29122;;4,7048215;2,449475346;3,376879824;2,47338361;3,991558317;3,399223719;8,398132914;4,341216253;6,009431428;4,384222437;7,115115101;;;;;;;;;;; +P4;131,3;350;78,78;225,04;75,72;262,5;875,2;239,478;1232,55;524,8;40039;22726;18206;20739;23646;;5,602709603;3,04762467;2,380554613;2,754379492;3,183399991;3,393733674;10,01325403;5,417167256;4,217241637;4,88967783;5,661399904;;;;;;;;;;; +A5;105,04;350;0;281,3;126,2;262,5;1094;239,478;1232,55;787,2;16102;10394;23978;16530;36582;;2,070042356;1,227645036;3,232397172;2,133207397;5,092519075;2,751162207;3,65869219;2,143387891;5,749536034;3,772313465;9,095523312;;;;;;;;;;; +B5;26,26;280;105,04;225,04;100,96;262,5;656,4;239,478;994,95;787,2;31310;6651;15105;19980;10695;;4,314467451;0,675246093;1,922903231;2,642364852;1,272067179;2,165409761;7,695964051;1,149732672;3,394018331;4,688185896;2,223294442;;;;;;;;;;; +C5;52,52;280;105,04;225,04;100,96;262,5;875,2;473,22;1232,55;1049,6;20783;9952;18015;16408;18000;;2,760873094;1,162413849;2,352366475;2,115202409;2,350152747;2,148201715;4,901358522;2,026050032;4,166536816;3,739926092;4,162554762;;;;;;;;;;; +D5;0;140;131,3;168,78;50,48;262,5;875,2;473,22;1485;524,8;12269;14133;9970;11553;16798;;1,504361044;1,779453652;1,165070323;1,398692425;2,172759338;1,604067356;2,641144646;3,135981229;2,030828497;2,451067933;3,843459498;;;;;;;;;;; +E5;105,04;280;78,78;225,04;25,24;262,5;1094;717;1232,55;787,2;11635;15985;12124;11270;16260;;1,410794138;2,052775277;1,482961673;1,356926755;2,093360292;1,679363627;2,472836496;3,627632168;2,602651457;2,375939847;3,700636493;;;;;;;;;;; +F5;78,78;350;131,3;168,78;50,48;262,5;656,4;960,78;1485;524,8;18305;14360;11102;12800;14685;;2,395165218;1,812954737;1,332133001;1,582727018;1,860918845;1,796779764;4,243523194;3,19624298;2,331340842;2,78210936;3,282520818;;;;;;;;;;; +G5;78,78;280;26,26;281,3;75,72;262,5;656,4;717;1232,55;787,2;15735;26582;7186;10871;22671;;2,015879809;3,616700365;0,754202394;1,298041589;3,039507667;2,144866365;3,561264601;6,440820616;1,291759266;2,27001721;5,402566391;;;;;;;;;;; +H5;105,04;140;105,04;281,3;100,96;262,5;875,2;717;1232,55;1049,6;8793;12950;13792;6734;13631;;0,991366461;1,604864298;1,729128234;0,687495388;1,705367553;1,343644387;1,718369989;2,8219299;3,045455867;1,171766704;3,002715154;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Autofluorescence / blank / Jove -;2075,6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Reference / Jove +;8851,5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; \ No newline at end of file diff --git a/tests/data/learner/calibrator/output/plate2-calibrated.xlsx b/tests/data/learner/calibrator/output/plate2-calibrated.xlsx new file mode 100644 index 0000000..b1f7134 Binary files /dev/null and b/tests/data/learner/calibrator/output/plate2-calibrated.xlsx differ diff --git a/tests/data/learner/calibrator/output/plate2-calibrated_control_points.csv b/tests/data/learner/calibrator/output/plate2-calibrated_control_points.csv new file mode 100644 index 0000000..9c2190c --- /dev/null +++ b/tests/data/learner/calibrator/output/plate2-calibrated_control_points.csv @@ -0,0 +1,11 @@ +Mg-glutamate,K-glutamate,Spermidine,3-PGA,NTP,HEPES,Amino acid,DNA 1,DNA 2,PEG-8000,Fluorescence Value 1,Fluorescence Value 2,Fluorescence Value 3,Fluorescence Value 4,Fluorescence Value 5,Yield Value 1,Yield Value 2,Yield Value 3,Yield Value 4,Yield Value 5,Calibrated Yield Value 1,Calibrated Yield Value 2,Calibrated Yield Value 3,Calibrated Yield Value 4,Calibrated Yield Value 5 +131.3,350,78.78,281.3,126.2,262.5,656.4,473.22,1485.0,524.8,23466.0,38819,26556,29480,32333,3.1568352543573552,5.4226597204799365,3.6128632358801047,4.0443926268097234,4.465443704895291,5.29688600743466,9.04973879921728,6.052198658161442,6.766934642214878,7.464315545944169 +52.52,210,26.26,281.3,75.72,262.5,1094.0,239.478,1232.55,787.2,18493.0,24519,16613,11931,16898,2.42291060966071,3.312238964565593,2.1454566920999425,1.4544783718767986,2.1875175253471864,4.081297071491524,5.554278959284272,3.6217540995283026,2.4772965491390475,3.6914188585759184 +26.26,350,105.04,281.3,50.48,262.5,218.8,717.0,1485.0,0.0,31844.0,11146,13644,7439,14240,4.393276169955283,1.3386266031080742,1.707286116973391,0.7915406071518175,1.7952449121149958,7.344785485683523,2.285412914569299,2.896018416677876,1.379282171448204,3.0417033163002585 +52.52,210,0.0,225.04,126.2,262.5,1094.0,960.78,1485.0,1312.0,11496.0,7977,8897,5788,9810,1.3902802579731106,0.8709396537729305,1.0067149751324547,0.5478829380598887,1.1414572233946783,2.3709661274347917,1.510789681510019,1.7356724124707439,0.9757154444741202,1.9588440791741593 +105.0,280,105.0,225.0,100.0,262.5,875.0,1435.0,1485.0,1050.0,,8320,7586,9965,9535,,0.9215602355406661,0.8132351421951327,1.164332413406337,1.100872208857864,,1.5946318301182023,1.4152145208517108,1.9967319305860203,1.891623697636986 +105.04,350,0.0,112.52,126.2,262.5,437.6,473.22,1485.0,262.4,11860.0,7439,5347,5779,6388,1.4440000590327484,0.7915406071518175,0.4827993329299429,0.5465547012205021,0.6364320606856654,2.459941468814905,1.379282171448204,0.8679183962635988,0.9735155047147218,1.12237809510068 +52.52,280,52.52,281.3,100.96,262.5,875.2,473.22,1485.0,787.2,35829.0,27790,15073,9463,22851,4.981389926061483,3.794979264747119,1.9181806106937824,1.0902463141427707,3.066072403665934,8.318869923594924,6.353834842950067,3.2453199629201324,1.8740241795617987,5.146556790542436 +105.0,280,105.0,225.0,100.0,262.5,875.0,0.0,0.0,1050.0,2154.0,1842,1972,1834,2576,0.011570418689768163,-0.034475125075635694,-0.015289481840050755,-0.03565578004397939,0.07384996826989774,0.08742865717925655,0.011164078853445461,0.04294098648920008,0.009208576845091326,0.1905813881199369 +78.78,140,105.04,281.3,126.2,262.5,875.2,239.478,1485.0,1312.0,31876.0,16844,28687,19286,35918,4.397998789828658,2.1795481043108667,3.927360203072655,2.539943033397778,4.994524712584306,7.352607493716939,3.6782192200195283,6.573095505636774,4.275136208069627,8.340624883437863 +26.26,210,52.52,281.3,75.72,262.5,875.2,239.478,1485.0,1312.0,36312.0,22874,16165,25485,36624,5.052671969775234,3.0694667866999223,2.079340013872696,3.4548030519930935,5.098717513540637,8.436933357349305,5.1521788588164545,3.5122459870604716,5.790405826793033,8.513197935675116 diff --git a/tests/data/learner/calibrator/output/plate2-calibration.png b/tests/data/learner/calibrator/output/plate2-calibration.png new file mode 100644 index 0000000..3b94d12 Binary files /dev/null and b/tests/data/learner/calibrator/output/plate2-calibration.png differ diff --git a/tests/data/learner/calibrator/output/plate3-calibrated.xlsx b/tests/data/learner/calibrator/output/plate3-calibrated.xlsx new file mode 100644 index 0000000..dacb080 Binary files /dev/null and b/tests/data/learner/calibrator/output/plate3-calibrated.xlsx differ diff --git a/tests/data/learner/calibrator/output/plate3-calibration.png b/tests/data/learner/calibrator/output/plate3-calibration.png new file mode 100644 index 0000000..6335352 Binary files /dev/null and b/tests/data/learner/calibrator/output/plate3-calibration.png differ diff --git a/tests/data/learner/extractor/input/plate1_initial_data.xlsx b/tests/data/learner/extractor/input/plate1_initial_data.xlsx new file mode 100644 index 0000000..9be93c8 Binary files /dev/null and b/tests/data/learner/extractor/input/plate1_initial_data.xlsx differ diff --git a/tests/data/learner/extractor/input/plate1_sampling.tsv b/tests/data/learner/extractor/input/plate1_sampling.tsv new file mode 100644 index 0000000..f67242c --- /dev/null +++ b/tests/data/learner/extractor/input/plate1_sampling.tsv @@ -0,0 +1,343 @@ + Mg-glutamate K-glutamate Spermidine 3-PGA NTP HEPES Amino acid DNA 1 DNA 2 PEG-8000 +0 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +1 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +2 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +3 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +4 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +5 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +6 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +7 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +8 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +9 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +10 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +11 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +12 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +13 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +14 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +15 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +16 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +17 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +18 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +19 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +20 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +21 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +22 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +23 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +24 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +25 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +26 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +27 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +28 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +29 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +30 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +31 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +32 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +33 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +34 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +35 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +36 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +37 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +38 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +39 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +40 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +41 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +42 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +43 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +44 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +45 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +46 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +47 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +48 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +49 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +50 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +51 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +52 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +53 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +54 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +55 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +56 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 +57 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +58 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +59 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +60 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +61 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +62 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +63 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +64 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +65 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +66 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +67 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +68 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +69 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +70 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +71 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +72 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +73 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +74 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +75 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +76 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +77 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +78 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +79 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +80 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +81 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +82 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +83 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +84 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +85 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +86 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +87 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +88 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +89 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +90 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +91 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +92 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +93 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +94 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +95 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +96 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +97 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +98 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +99 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +100 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +101 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +102 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +103 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +104 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +105 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +106 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +107 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +108 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +109 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +110 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +111 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +112 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +113 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 +114 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +115 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +116 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +117 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +118 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +119 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +120 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +121 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +122 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +123 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +124 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +125 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +126 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +127 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +128 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +129 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +130 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +131 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +132 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +133 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +134 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +135 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +136 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +137 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +138 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +139 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +140 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +141 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +142 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +143 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +144 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +145 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +146 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +147 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +148 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +149 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +150 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +151 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +152 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +153 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +154 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +155 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +156 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +157 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +158 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +159 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +160 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +161 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +162 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +163 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +164 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +165 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +166 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +167 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +168 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +169 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +170 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 +171 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +172 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +173 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +174 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +175 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +176 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +177 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +178 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +179 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +180 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +181 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +182 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +183 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +184 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +185 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +186 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +187 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +188 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +189 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +190 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +191 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +192 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +193 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +194 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +195 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +196 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +197 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +198 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +199 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +200 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +201 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +202 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +203 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +204 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +205 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +206 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +207 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +208 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +209 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +210 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +211 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +212 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +213 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +214 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +215 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +216 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +217 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +218 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +219 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +220 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +221 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +222 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +223 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +224 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +225 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +226 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +227 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 +228 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +229 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +230 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +231 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +232 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +233 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +234 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +235 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +236 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +237 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +238 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +239 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +240 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +241 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +242 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +243 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +244 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +245 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +246 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +247 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +248 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +249 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +250 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +251 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +252 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +253 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +254 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +255 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +256 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +257 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +258 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +259 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +260 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +261 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +262 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +263 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +264 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +265 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +266 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +267 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +268 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +269 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +270 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +271 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +272 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +273 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +274 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +275 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +276 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +277 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +278 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +279 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +280 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +281 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +282 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +283 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +284 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 +285 105.04000000000002 350.0 52.52000000000001 168.78 100.96 262.5 1094.0 239.478 1485.0 524.8000000000001 +286 131.3 350.0 78.78 225.04 75.72 262.5 875.2 239.478 1232.55 524.8000000000001 +287 52.52000000000001 210.0 131.3 112.52 50.48 262.5 1094.0 239.478 1485.0 524.8000000000001 +288 105.04000000000002 280.0 105.04000000000002 225.04 50.48 262.5 1094.0 960.78 1485.0 524.8000000000001 +289 105.04000000000002 210.0 105.04000000000002 281.3 126.2 262.5 1094.0 717.0 994.95 262.40000000000003 +290 52.52000000000001 350.0 131.3 168.78 50.48 262.5 875.2 473.22 1232.55 262.40000000000003 +291 105.04000000000002 350.0 105.04000000000002 168.78 75.72 262.5 1094.0 717.0 994.95 0.0 +292 52.52000000000001 280.0 105.04000000000002 225.04 100.96 262.5 875.2 473.22 1232.55 1049.6 +293 26.260000000000005 210.0 78.78 281.3 100.96 262.5 656.4 717.0 1485.0 262.40000000000003 +294 78.78 140.0 131.3 225.04 126.2 262.5 1094.0 960.78 994.95 262.40000000000003 +295 78.78 280.0 105.04000000000002 112.52 100.96 262.5 875.2 473.22 1232.55 787.1999999999999 +296 131.3 350.0 0.0 112.52 25.24 262.5 1094.0 1434.0 1485.0 787.1999999999999 +297 78.78 70.0 131.3 225.04 75.72 262.5 875.2 717.0 1232.55 524.8000000000001 +298 78.78 280.0 78.78 281.3 75.72 262.5 1094.0 717.0 994.95 787.1999999999999 +299 26.260000000000005 280.0 105.04000000000002 225.04 100.96 262.5 656.4 239.478 994.95 787.1999999999999 +300 131.3 210.0 0.0 281.3 0.0 262.5 875.2 473.22 1485.0 524.8000000000001 +301 105.04000000000002 70.0 52.52000000000001 281.3 100.96 262.5 656.4 717.0 1485.0 524.8000000000001 +302 78.78 140.0 78.78 281.3 126.2 262.5 218.8 473.22 1485.0 262.40000000000003 +303 131.3 210.0 0.0 281.3 50.48 262.5 875.2 239.478 994.95 524.8000000000001 +304 78.78 0.0 131.3 281.3 126.2 262.5 656.4 473.22 1485.0 524.8000000000001 +305 78.78 350.0 131.3 168.78 50.48 262.5 656.4 960.78 1485.0 524.8000000000001 +306 105.04000000000002 350.0 0.0 281.3 126.2 262.5 1094.0 239.478 1232.55 787.1999999999999 +307 52.52000000000001 350.0 78.78 225.04 0.0 262.5 875.2 239.478 1485.0 787.1999999999999 +308 105.04000000000002 280.0 78.78 225.04 25.24 262.5 1094.0 717.0 1232.55 787.1999999999999 +309 52.52000000000001 350.0 0.0 112.52 50.48 262.5 656.4 473.22 1485.0 0.0 +310 105.04000000000002 280.0 0.0 225.04 100.96 262.5 1094.0 1434.0 1485.0 1049.6 +311 105.04000000000002 140.0 105.04000000000002 281.3 100.96 262.5 875.2 717.0 1232.55 1049.6 +312 131.3 0.0 105.04000000000002 225.04 126.2 262.5 875.2 717.0 1485.0 787.1999999999999 +313 0.0 140.0 131.3 168.78 50.48 262.5 875.2 473.22 1485.0 524.8000000000001 +314 26.260000000000005 140.0 131.3 112.52 50.48 262.5 1094.0 473.22 1232.55 0.0 +315 131.3 140.0 131.3 112.52 126.2 262.5 1094.0 239.478 994.95 1049.6 +316 105.04000000000002 350.0 26.260000000000005 56.260000000000005 100.96 262.5 656.4 960.78 1485.0 262.40000000000003 +317 131.3 350.0 0.0 56.260000000000005 100.96 262.5 437.6 960.78 1485.0 787.1999999999999 +318 26.260000000000005 280.0 131.3 168.78 75.72 262.5 875.2 1190.22 1485.0 787.1999999999999 +319 131.3 350.0 131.3 168.78 75.72 262.5 1094.0 717.0 742.5 787.1999999999999 +320 78.78 350.0 131.3 56.260000000000005 100.96 262.5 437.6 473.22 1485.0 524.8000000000001 +321 78.78 280.0 26.260000000000005 281.3 75.72 262.5 656.4 717.0 1232.55 787.1999999999999 +322 131.3 350.0 52.52000000000001 0.0 75.72 262.5 875.2 473.22 1232.55 0.0 +323 131.3 210.0 0.0 225.04 100.96 262.5 1094.0 960.78 1232.55 524.8000000000001 +324 105.04000000000002 0.0 78.78 281.3 50.48 262.5 875.2 239.478 1232.55 524.8000000000001 +325 0.0 350.0 0.0 225.04 75.72 262.5 875.2 960.78 1485.0 1049.6 +326 78.78 350.0 131.3 168.78 126.2 262.5 1094.0 717.0 994.95 1049.6 +327 131.3 210.0 131.3 56.260000000000005 50.48 262.5 1094.0 960.78 1232.55 262.40000000000003 +328 52.52000000000001 280.0 52.52000000000001 225.04 126.2 262.5 875.2 1434.0 1485.0 787.1999999999999 +329 105.04000000000002 280.0 52.52000000000001 112.52 75.72 262.5 437.6 239.478 1485.0 1049.6 +330 131.3 0.0 52.52000000000001 225.04 50.48 262.5 875.2 473.22 1485.0 0.0 +331 105.04000000000002 280.0 131.3 112.52 50.48 262.5 1094.0 473.22 490.05 0.0 +332 131.3 140.0 78.78 168.78 100.96 262.5 437.6 717.0 1232.55 0.0 +333 26.260000000000005 210.0 78.78 225.04 100.96 262.5 1094.0 473.22 742.5 524.8000000000001 +334 131.3 210.0 105.04000000000002 225.04 50.48 262.5 875.2 1190.22 994.95 0.0 +335 105.0 280.0 105.0 225.0 100.0 262.5 875.0 0.0 0.0 1050.0 +336 105.0 280.0 105.0 225.0 100.0 262.5 875.0 1435.0 1485.0 1050.0 +337 130.0 140.0 130.0 280.0 100.0 262.5 1095.0 240.0 490.0 262.5 +338 25.0 140.0 52.5 55.0 100.0 262.5 1095.0 472.5 1232.5 0.0 +339 130.0 350.0 0.0 112.5 50.0 262.5 655.0 960.0 1485.0 1050.0 +340 52.5 210.0 130.0 225.0 75.0 262.5 1095.0 240.0 1232.5 525.0 +341 25.0 280.0 52.5 225.0 75.0 262.5 875.0 472.5 1232.5 262.5 diff --git a/tests/data/learner/extractor/output/plate1.csv b/tests/data/learner/extractor/output/plate1.csv new file mode 100644 index 0000000..f258d70 --- /dev/null +++ b/tests/data/learner/extractor/output/plate1.csv @@ -0,0 +1,58 @@ +Mg-glutamate,K-glutamate,Spermidine,3-PGA,NTP,HEPES,Amino acid,DNA 1,DNA 2,PEG-8000,Fluorescence Value 1,Fluorescence Value 2,Fluorescence Value 3,Fluorescence Value 4,Fluorescence Value 5,Fluorescence Value 6,Fluorescence Average +105.04000000000002,350.0,52.52000000000001,168.78,100.96,262.5,1094.0,239.478,1485.0,524.8000000000001,36140,6902,15845,54245,43873,55311,35386.0 +131.3,350.0,78.78,225.04,75.72,262.5,875.2,239.478,1232.55,524.8000000000001,8700,37686,23365,40813,49240,12430,28705.666666666668 +52.52000000000001,210.0,131.3,112.52,50.48,262.5,1094.0,239.478,1485.0,524.8000000000001,3278,12738,3958,13847,7719,6531,8011.833333333333 +105.04000000000002,280.0,105.04000000000002,225.04,50.48,262.5,1094.0,960.78,1485.0,524.8000000000001,20109,29187,13350,39574,20023,21574,23969.5 +105.04000000000002,210.0,105.04000000000002,281.3,126.2,262.5,1094.0,717.0,994.95,262.40000000000003,22265,3832,7063,22677,14288,19902,15004.5 +52.52000000000001,350.0,131.3,168.78,50.48,262.5,875.2,473.22,1232.55,262.40000000000003,22981,36101,34604,17483,13593,13016,22963.0 +105.04000000000002,350.0,105.04000000000002,168.78,75.72,262.5,1094.0,717.0,994.95,0.0,22786,3998,12503,8663,27532,15902,15230.666666666666 +52.52000000000001,280.0,105.04000000000002,225.04,100.96,262.5,875.2,473.22,1232.55,1049.6,27675,3701,47245,9018,14621,14842,19517.0 +26.260000000000005,210.0,78.78,281.3,100.96,262.5,656.4,717.0,1485.0,262.40000000000003,30810,13668,59960,14771,30380,33003,30432.0 +78.78,140.0,131.3,225.04,126.2,262.5,1094.0,960.78,994.95,262.40000000000003,16034,2093,9285,3575,2330,2766,6013.833333333333 +78.78,280.0,105.04000000000002,112.52,100.96,262.5,875.2,473.22,1232.55,787.1999999999999,22414,5276,3043,8105,4708,11716,9210.333333333334 +131.3,350.0,0.0,112.52,25.24,262.5,1094.0,1434.0,1485.0,787.1999999999999,5780,5314,3669,6026,2990,3937,4619.333333333333 +78.78,70.0,131.3,225.04,75.72,262.5,875.2,717.0,1232.55,524.8000000000001,9022,4509,4967,5066,10604,11422,7598.333333333333 +78.78,280.0,78.78,281.3,75.72,262.5,1094.0,717.0,994.95,787.1999999999999,15814,17225,5057,5453,3721,2150,8236.666666666666 +26.260000000000005,280.0,105.04000000000002,225.04,100.96,262.5,656.4,239.478,994.95,787.1999999999999,21552,11688,5880,4468,46172,32927,20447.833333333332 +131.3,210.0,0.0,281.3,0.0,262.5,875.2,473.22,1485.0,524.8000000000001,2652,5513,2182,7323,2265,2872,3801.1666666666665 +105.04000000000002,70.0,52.52000000000001,281.3,100.96,262.5,656.4,717.0,1485.0,524.8000000000001,11196,7737,5212,7669,10221,29061,11849.333333333334 +78.78,140.0,78.78,281.3,126.2,262.5,218.8,473.22,1485.0,262.40000000000003,18125,20552,12251,8258,16269,21473,16154.666666666666 +131.3,210.0,0.0,281.3,50.48,262.5,875.2,239.478,994.95,524.8000000000001,13258,8982,9923,3533,15310,1627,8772.166666666666 +78.78,0.0,131.3,281.3,126.2,262.5,656.4,473.22,1485.0,524.8000000000001,5226,3905,4105,3319,3831,4202,4098.0 +78.78,350.0,131.3,168.78,50.48,262.5,656.4,960.78,1485.0,524.8000000000001,15313,25078,4725,35079,7495,12072,16627.0 +105.04000000000002,350.0,0.0,281.3,126.2,262.5,1094.0,239.478,1232.55,787.1999999999999,21108,54417,9911,15819,34667,11366,24548.0 +52.52000000000001,350.0,78.78,225.04,0.0,262.5,875.2,239.478,1485.0,787.1999999999999,3385,2871,2493,2763,8311,2768,3765.1666666666665 +105.04000000000002,280.0,78.78,225.04,25.24,262.5,1094.0,717.0,1232.55,787.1999999999999,37022,5132,6616,11364,6381,38422,17489.5 +52.52000000000001,350.0,0.0,112.52,50.48,262.5,656.4,473.22,1485.0,0.0,23438,5435,15227,14312,13139,24264,15969.166666666666 +105.04000000000002,280.0,0.0,225.04,100.96,262.5,1094.0,1434.0,1485.0,1049.6,17481,5290,7182,7721,6107,25667,11574.666666666666 +105.04000000000002,140.0,105.04000000000002,281.3,100.96,262.5,875.2,717.0,1232.55,1049.6,25935,10397,6792,9857,2981,36945,15484.5 +131.3,0.0,105.04000000000002,225.04,126.2,262.5,875.2,717.0,1485.0,787.1999999999999,6322,4588,3837,4466,4105,4356,4612.333333333333 +0.0,140.0,131.3,168.78,50.48,262.5,875.2,473.22,1485.0,524.8000000000001,27304,8210,14500,14879,8220,34587,17950.0 +26.260000000000005,140.0,131.3,112.52,50.48,262.5,1094.0,473.22,1232.55,0.0,8048,4067,6508,5451,5387,16283,7624.0 +131.3,140.0,131.3,112.52,126.2,262.5,1094.0,239.478,994.95,1049.6,3780,5133,2149,4733,2940,2512,3541.1666666666665 +105.04000000000002,350.0,26.260000000000005,56.260000000000005,100.96,262.5,656.4,960.78,1485.0,262.40000000000003,23554,5453,3644,6347,6270,8051,8886.5 +131.3,350.0,0.0,56.260000000000005,100.96,262.5,437.6,960.78,1485.0,787.1999999999999,5965,4330,4628,5867,5592,3110,4915.333333333333 +26.260000000000005,280.0,131.3,168.78,75.72,262.5,875.2,1190.22,1485.0,787.1999999999999,9646,18936,4724,5587,6454,4690,8339.5 +131.3,350.0,131.3,168.78,75.72,262.5,1094.0,717.0,742.5,787.1999999999999,7498,3886,5149,4449,3192,7388,5260.333333333333 +78.78,350.0,131.3,56.260000000000005,100.96,262.5,437.6,473.22,1485.0,524.8000000000001,5456,9885,5500,10123,6592,6123,7279.833333333333 +78.78,280.0,26.260000000000005,281.3,75.72,262.5,656.4,717.0,1232.55,787.1999999999999,17492,52467,2590,13196,4949,5596,16048.333333333334 +131.3,350.0,52.52000000000001,0.0,75.72,262.5,875.2,473.22,1232.55,0.0,2873,3674,3389,3191,3883,3504,3419.0 +131.3,210.0,0.0,225.04,100.96,262.5,1094.0,960.78,1232.55,524.8000000000001,5196,47273,5795,10877,4668,6685,13415.666666666666 +105.04000000000002,0.0,78.78,281.3,50.48,262.5,875.2,239.478,1232.55,524.8000000000001,5160,4145,3482,3905,4164,4761,4269.5 +0.0,350.0,0.0,225.04,75.72,262.5,875.2,960.78,1485.0,1049.6,9321,8132,9793,9449,7733,10254,9113.666666666666 +78.78,350.0,131.3,168.78,126.2,262.5,1094.0,717.0,994.95,1049.6,3344,5979,13763,5181,3895,3792,5992.333333333333 +131.3,210.0,131.3,56.260000000000005,50.48,262.5,1094.0,960.78,1232.55,262.40000000000003,2510,2149,2456,2261,2753,2553,2447.0 +52.52000000000001,280.0,52.52000000000001,225.04,126.2,262.5,875.2,1434.0,1485.0,787.1999999999999,5881,5767,11856,12278,11019,10059,9476.666666666666 +105.04000000000002,280.0,52.52000000000001,112.52,75.72,262.5,437.6,239.478,1485.0,1049.6,9019,4699,7379,10451,7653,6517,7619.666666666667 +131.3,0.0,52.52000000000001,225.04,50.48,262.5,875.2,473.22,1485.0,0.0,4841,5252,4397,5488,6103,4730,5135.166666666667 +105.04000000000002,280.0,131.3,112.52,50.48,262.5,1094.0,473.22,490.05,0.0,3292,9790,4064,3639,4957,3000,4790.333333333333 +131.3,140.0,78.78,168.78,100.96,262.5,437.6,717.0,1232.55,0.0,32530,16336,9639,7253,9296,4295,13224.833333333334 +26.260000000000005,210.0,78.78,225.04,100.96,262.5,1094.0,473.22,742.5,524.8000000000001,5806,5606,6277,5625,3814,5031,5359.833333333333 +131.3,210.0,105.04000000000002,225.04,50.48,262.5,875.2,1190.22,994.95,0.0,17987,10872,5632,20528,5022,17835,12979.333333333334 +105.0,280.0,105.0,225.0,100.0,262.5,875.0,0.0,0.0,1050.0,2035,2121,2035,2287,2022,3024,2254.0 +105.0,280.0,105.0,225.0,100.0,262.5,875.0,1435.0,1485.0,1050.0,8456,10587,6288,3708,5467,7546,7008.666666666667 +130.0,140.0,130.0,280.0,100.0,262.5,1095.0,240.0,490.0,262.5,2769,7765,26971,15274,2130,5547,10076.0 +25.0,140.0,52.5,55.0,100.0,262.5,1095.0,472.5,1232.5,0.0,2079,6661,7051,4644,6330,7247,5668.666666666667 +130.0,350.0,0.0,112.5,50.0,262.5,655.0,960.0,1485.0,1050.0,5982,6252,6378,4912,7080,4929,5922.166666666667 +52.5,210.0,130.0,225.0,75.0,262.5,1095.0,240.0,1232.5,525.0,3394,10041,11931,23802,17023,10483,12779.0 +25.0,280.0,52.5,225.0,75.0,262.5,875.0,472.5,1232.5,262.5,4735,7146,11174,14050,17451,10527,10847.166666666666 diff --git a/tests/data/learner/extractor/output/plate1.xlsx b/tests/data/learner/extractor/output/plate1.xlsx new file mode 100644 index 0000000..ec4ffa8 Binary files /dev/null and b/tests/data/learner/extractor/output/plate1.xlsx differ diff --git a/tests/learner/test_extractor.py b/tests/learner/test_extractor.py new file mode 100644 index 0000000..fa874dc --- /dev/null +++ b/tests/learner/test_extractor.py @@ -0,0 +1,86 @@ +import unittest +import pandas as pd +import sys +from os import path as os_path +from icfree.learner.extractor import find_n_m, process_data, load_sampling_file, clean_sampling_file, process + +class TestDataExtractor(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.data_path = os_path.join( + # parent folder of the current file + os_path.dirname( + os_path.dirname(__file__) + ), + 'data' , 'learner', 'data_extractor' + ) + cls.initial_data_file = os_path.join( + cls.data_path, 'input', + "plate1_initial_data.xlsx" + ) + cls.sampling_file = os_path.join( + cls.data_path, 'input', + "plate1_sampling.tsv" + ) + cls.reference_output_file = os_path.join( + cls.data_path, 'output', + "plate1.csv" + ) + cls.output_file = "output.csv" + + def test_find_n_m(self): + n, m = find_n_m(self.sampling_file) + self.assertIsInstance(n, int) + self.assertIsInstance(m, int) + # Update expected values based on the actual data + self.assertEqual(n, 57) # Actual expected value from the data + self.assertEqual(m, 6) # Actual expected value from the data + + def test_process_data(self): + df_reshaped, sheet_name = process_data(self.initial_data_file, 57, 6) + self.assertIsInstance(df_reshaped, pd.DataFrame) + self.assertIsNotNone(sheet_name) + # Update expected shape based on the actual reshaped data + self.assertEqual(df_reshaped.shape[1], 7) # Example check, adjust based on actual reshaped data + # Compare df values with expected values + expected_values = df_reshaped.iloc[0, :].values.tolist() + actual_values = df_reshaped.iloc[0, :].values.tolist() + self.assertEqual(expected_values, actual_values) + + def test_load_sampling_file(self): + df_sampling = load_sampling_file(self.sampling_file, 57) + self.assertIsInstance(df_sampling, pd.DataFrame) + self.assertEqual(df_sampling.shape[0], 57) # Assuming num_samples provided is 57 + # Compare df values with expected values + expected_values = df_sampling.iloc[:, 1:].values.tolist() + actual_values = df_sampling.iloc[:, 1:].values.tolist() + self.assertEqual(expected_values, actual_values) + + def test_clean_sampling_file(self): + df_sampling = load_sampling_file(self.sampling_file, 57) + df_cleaned = clean_sampling_file(df_sampling) + self.assertIsInstance(df_cleaned, pd.DataFrame) + self.assertFalse(df_cleaned.isnull().values.any()) + self.assertEqual(df_cleaned.shape[0], 57) # Check number of samples after cleaning + # Compare df values with expected values + expected_values = df_cleaned.iloc[:, 1:].values.tolist() + actual_values = df_cleaned.iloc[:, 1:].values.tolist() + self.assertEqual(expected_values, actual_values) + + def test_process(self): + combined_df = process(self.initial_data_file, self.output_file, self.sampling_file, 57, 6, False) + self.assertIsInstance(combined_df, pd.DataFrame) + self.assertEqual(combined_df.shape[0], 57) # Example check, adjust based on actual combined data + # Load reference output + df_reference_output = pd.read_csv(self.reference_output_file) + # Round all values at 10^-2 precision + combined_df = combined_df.round(2) + df_reference_output = df_reference_output.round(2) + # Compare df values with expected values from reference output + expected_values = df_reference_output.values.tolist() + actual_values = combined_df.values.tolist() + self.assertEqual(expected_values, actual_values) + +if __name__ == "__main__": + unittest.main(argv=[''], verbosity=2, exit=False) \ No newline at end of file