diff --git a/src/Decision_Tree/Functions.py b/src/Decision_Tree/Functions.py new file mode 100644 index 0000000..7199e64 --- /dev/null +++ b/src/Decision_Tree/Functions.py @@ -0,0 +1,107 @@ +""" +This file contains the functions used by the 'Main' file to convert the decision +tree generated in Python to the structured text language of ABB's 800xA software. + +A description of the functionality and parameters of each function is provided +within the function itself. + +""" + +def If_Elsif_Insertion(vector, filepath): + """ + This function adds the terms 'If' and 'Elsif' in the appropriate places. + Input Parameters: + vector = Number of vertical bars (|) in each line of the file; + filepath = Name of the file where the adjustments will be made. + """ + groups = [list(range(len(vector)))] + while groups: + current_group = groups.pop(0) + subgroups_to_analyze = [] + for i in current_group: + value = vector[i] + for j in current_group: + if i != j: + if vector[j] == value: + with open(filepath, 'r') as file: + lines = file.readlines() + lines[j] = lines[j].replace("---", "if") + lines[i] = lines[i].replace("---", "elsif") + with open(filepath, 'w') as file: + file.write(''.join(lines)) + subgroup1 = current_group[current_group.index(j) + 1:current_group.index(i)] + subgroup2 = current_group[current_group.index(i) + 1:] + subgroups_to_analyze.extend([subgroup1, subgroup2]) + break + else: + break + groups.extend(subgroups_to_analyze) + +def Decreased_indentation(filepath): + """ + This function analyzes line indentations to identify conditional structure + blocks. + Input parameters: + filepath = Name of the file where the reading will be performed. + Output parameters: + lines_with_smaller_indentation = Vector containing indices of lines that + have an indentation smaller than the previous line. + + """ + line_with_smaller_indentation = [] + with open(filepath, 'r') as file: + lines = file.readlines() + for i in range(1, len(lines)): + current_line = lines[i] + previous_line = lines[i - 1] + current_indentation = len(current_line) - len(current_line.lstrip()) + previous_indentation = len(previous_line) - len(previous_line.lstrip()) + if current_indentation == 0: + pass + elif current_indentation < previous_indentation: + line_with_smaller_indentation.append(i) + return line_with_smaller_indentation + +def Insertion_terms(filepath, index): + """ + This function identifies the position where the 'end_if' term should be + placed. + Input parameters: + filepath = Name of the file where the reading will be performed. + index = Vector that stores lines with indentation smaller than the + previous line. + Output parameters: + lines_with_smaller_indices = Vector that stores the indices of lines + where the term "end_if" should be added; + indentation = Vector that stores the number of spaces at the beginning + of lines stored in the index vector that have lines below with smaller + indentation; + tabulation = Vector that stores the number of spaces at the beginning of + lines stored in the index vector that do not have lines below with + smaller indentation. + + """ + + with open(filepath, 'r') as original_file: + lines = original_file.readlines() + lines_with_additions = []; lines_with_smaller_indices = []; indentation = [] + tabulation = [] + for i, line in enumerate(lines): + lines_with_additions.append(line) + if i in index: + indentationlinei = len(lines[i]) - len(lines[i].lstrip()) + j = i + 1 + while j < len(lines): + analyzed_line= lines[j] + analyzed_indentation = len(analyzed_line) - len(analyzed_line.lstrip()) + lines_limit = len(lines) - 1 + if analyzed_indentation < indentationlinei: + lines_with_smaller_indices.append(j) + indentation.append(indentationlinei) + break + elif j == lines_limit: + tabulation.append(len(lines[i]) - len(lines[i].lstrip())) + break + else: + j += 1 + return lines_with_smaller_indices, indentation, tabulation \ No newline at end of file diff --git a/src/Decision_Tree/Main.py b/src/Decision_Tree/Main.py new file mode 100644 index 0000000..1ffa17a --- /dev/null +++ b/src/Decision_Tree/Main.py @@ -0,0 +1,177 @@ +""" +This file performs the conversion of a decision tree structure (classification +or regression) generated in Python into a suitable version compatible with the +'structured text' language used in ABB's 800xA programming software. The goal +is to streamline the work of engineers in implementing decision trees in an +industrial environment. + +This file was designed considering the syntax of decision trees generated in +Python using the 'scikit-learn' library and having only a single output. +Therefore, decision trees that do not meet these requirements may not be +correctly converted. + +A brief description of how the code works: + + A .txt file containing the generated decision tree must be saved in the same + directory as this file. To generate the .txt file, we suggest appending the + following code at the end of the user-created file used to generate the + decision tree. + + --------------------------------------------------------------------------- + with open('filename.txt', 'w') as file: + file.write(tree.export_text(clf)) + + NOTE: + - Replace 'filename' with the desired name; + - Replace 'clf' with the name of the variable containing the tree. + --------------------------------------------------------------------------- + When starting this code, the user needs to provide the following information: + 1- Name of the .txt file containing the decision tree; + 2- The name of the output variable to be written in the converted tree. + + After entering the information, the code within this file, along with the + 'Functions' file, will generate a .txt file saved in the same directory as + this file. The generated file will contain a decision tree that preserves + the same functionality as the original decision tree. However, it will have + a syntax suitable for the 'structured text' language used by ABB's 800xA + software. + + Additionally, another file ('tabela.txt') is generated, which contains the + variables and parameters used in the code, as well as information such as + 'Data type', 'Direction', 'FD Port', and 'Attributes' + + Thus, users can directly copy the contents of the generated .txt files into + the 800xA software, requiring only minimal adjustments if necessary. + +""" +import numpy as np +import re +from Functions import If_Elsif_Insertion, Decreased_indentation, Insertion_terms + +# -------- Input tree information -------- + +# -------- Validation of the existence of the .txt file in the folder +while True: + original_name = input('Source file name: ') + original_file = original_name + '.txt' + + try: + # -------- Creating target file -------- + destination_file = original_name + '_800xA' + '.txt' + with open(original_file, 'rb') as original: + with open(destination_file, 'wb') as destiny: + destiny.write(original.read()) + + break + except FileNotFoundError: + print(f"ATTENTION!\n The file {original_file} does not exist in this folder. Please enter the original file name again.\ndf") + +# -------- Checking the tree type (1 = classification | 2 = regression) -------- + +with open(destination_file, 'r') as destiny: + content = destiny.read() +if 'class' in content: + tree_type = 1 +elif 'value' in content: + tree_type = 2 + +# -------- Counting and removal of slashes (|) -------- + +with open(destination_file, 'r') as file: + lines = file.readlines() +num_slashes = np.empty(len(lines), dtype=int) +for i in range(len(lines)): + num_slashes[i] = lines[i].count('|') + lines[i] = lines[i].replace("|", "") +with open(destination_file, "w") as file: + file.write(''.join(lines)) + +# -------- Insertion of If and Elsif -------- + +If_Elsif_Insertion(num_slashes, destination_file) + +# -------- Syntax adjustments -------- + +modifications = [("--- ", ""), (":", " :=")] +with open(destination_file, 'r') as file: + content = file.read() +for from_, to_ in modifications: + content = content.replace(from_, to_) +with open(destination_file, 'w') as file: + file.write(content) + +# -------- Create a list with the names of the input variables and add the name of the output variable -------- + +variables = set() +with open(destination_file, 'r') as file: + for line in file: + if line.strip(): + first_word = line.strip().lstrip('if').lstrip('elsif').split()[0] + if first_word not in ('value', 'class') and first_word not in variables: + variables.add(first_word) + while True: + output_variable = input("Enter the output variable: ") + if output_variable not in variables: + break + else: + print("ERROR: The output variable should be different from the input variables. Please provide a different variable.") + +# -------- Substituting the input and output variables -------- + +with open(destination_file, "r+") as file: + content = file.read() + if tree_type == 1: + content = re.sub(r'class := (.+)', r'class := \1;', content) + content = content.replace('class', output_variable) + elif tree_type == 2: + content = re.sub(r'value := \[([0-9.]+)\]', r'value := \1;', content) + content = content.replace('value', output_variable) + file.seek(0) + file.write(content) + file.truncate() + +# -------- Insertion of the term 'end_if' and ';' at the end of the lines -------- + +index = Decreased_indentation(destination_file) +calculated_indices, indentation, tabulation = Insertion_terms(destination_file, index) + +with open(destination_file, 'a') as file: + if tabulation is not None: + for added_space in reversed(tabulation): + file.write((' ' * added_space) + 'end_if;' + '\n') + file.write('end_if;' + '\n') + else: + file.write('end_if;' + '\n') + +with open (destination_file, 'r') as file: + lines = file.readlines() +for i in range(len(calculated_indices)): + line = calculated_indices[i] + for j in range(len(lines)): + previous_line = lines[j] + if j == line: + modified_line = (" " * indentation[i]) + 'end_if;' + '\n' + previous_line + lines[j] = modified_line +with open(destination_file, 'w') as file: + file.write(''.join(lines)) + +# -------- Inclusion of the term 'then' -------- + +with open(destination_file, 'r') as file: + original_text = file.read() +modified_text = re.sub(r'if (.+)', r'if (\1) then', original_text) +with open(destination_file, 'w') as file: + file.write(modified_text) + +# -------- Construction of the variables table -------- + +table_file = original_name + '_table.txt' +with open(table_file, 'w') as file: + file.write('Parameters:\n') + for variable in variables: + line = f'{variable}\treal\t\tin\tyes\n' + file.write(line) + if tree_type == 1: + file.write(f'{output_variable}\tdint\t\tout\tyes\n') + elif tree_type == 2: + file.write(f'{output_variable}\treal\t\tout\tyes\n') \ No newline at end of file diff --git a/src/Example/generate_DT.py b/src/Example/generate_DT.py new file mode 100644 index 0000000..78cc435 --- /dev/null +++ b/src/Example/generate_DT.py @@ -0,0 +1,24 @@ +import pandas as pd +from sklearn.model_selection import train_test_split +from sklearn.tree import DecisionTreeRegressor +from sklearn import tree + +df = pd.read_csv("mass_flow_rate_estimation.csv", header=0) +df = df.replace(',', '.', regex=True) +df = df.astype(float) + + +X = df[['med10', 'sd10']] +y = df['bal75'] + +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) + +reg = DecisionTreeRegressor(max_depth=3) +reg.fit(X_train, y_train) + +feature_names = list(X.columns) +feature_names=feature_names + +with open('filename.txt', 'w') as file: + file.write(tree.export_text(reg, feature_names=feature_names)) + \ No newline at end of file diff --git a/src/Example/generate_MLP.py b/src/Example/generate_MLP.py new file mode 100644 index 0000000..9f5fe51 --- /dev/null +++ b/src/Example/generate_MLP.py @@ -0,0 +1,37 @@ +import pandas as pd +from sklearn.neural_network import MLPRegressor +from sklearn.model_selection import train_test_split + +df = pd.read_csv("mass_flow_rate_estimation.csv", header=0) +df = df.replace(',', '.', regex=True) +df = df.astype(float) + +X = df[["med10", "sd10"]] +y = df["bal75"] +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + +activation_function = 'tanh' +mlp = MLPRegressor(hidden_layer_sizes=(2,), activation=activation_function, max_iter=1000, random_state=42) +mlp.fit(X_train, y_train) + +with open('filename.txt', 'w') as file: + num_layers = len(mlp.hidden_layer_sizes) + 2 + file.write(f"Number of layers: {num_layers}\n") + file.write(f"Activation Function: {activation_function}\n") + file.write(f"Activation Function of the Output Layer: {mlp.out_activation_}\n") + file.write('\n') + file.write("Input layer:\n") + for i, variable in enumerate(X_train.columns): + file.write(f" Input Neuron {i + 1}: {variable}\n") + file.write('\n') + for j, (layer, biases) in enumerate(zip(mlp.coefs_, mlp.intercepts_)): + file.write(f"Layer {j + 1} - Neurons: {layer.shape[1]}\n") + file.write("Weights:\n") + for neuron_dest in range(layer.shape[1]): + file.write(f"Neuron {neuron_dest}:\n") + for neuron_src, weight in enumerate(layer[:, neuron_dest]): + file.write(f" Weight from neuron {neuron_src}: {weight:.2f}\n") + file.write("Biases:\n") + for neuron, bias in enumerate(biases): + file.write(f" Bias from neuron {neuron}: {bias:.2f}\n") + file.write("\n") \ No newline at end of file diff --git a/src/Example/mass_flow_rate_estimation.csv b/src/Example/mass_flow_rate_estimation.csv new file mode 100644 index 0000000..84200fa --- /dev/null +++ b/src/Example/mass_flow_rate_estimation.csv @@ -0,0 +1,39 @@ +med10,sd10,bal75 +"23,04353","0,103135","1774,45" +"23,095247","0,179946","1776,8" +"23,166933","0,261907","1779,15" +"23,258586","0,344382","1781,5" +"23,370208","0,423144","1783,851" +"23,501797","0,493915","1786,201" +"23,653355","0,551948","1788,551" +"23,82488","0,591455","1790,901" +"24,016374","0,604563","1793,251" +"24,193131","0,570068","1794,511" +"24,329952","0,495926","1794,511" +"24,426837","0,405978","1794,511" +"24,483786","0,327718","1794,511" +"24,500799","0,298073","1794,511" +"24,477876","0,337185","1794,511" +"24,415016","0,419325","1794,511" +"24,312221","0,50846","1794,511" +"24,169489","0,57829","1794,511" +"23,986821","0,604563","1794,511" +"23,803863","0,578707","1796,988" +"23,650872","0,518802","1802,517" +"23,52785","0,438389","1808,046" +"23,434796","0,349183","1813,575" +"23,37171","0,26522","1819,104" +"23,338592","0,208297","1824,633" +"23,335442","0,202598","1830,162" +"23,36226","0,23939","1835,691" +"23,419046","0,283153","1841,22" +"23,5058","0,302765","1846,749" +"23,60022","0,293935","1848,422" +"23,68464","0,272566","1845,047" +"23,75906","0,242394","1841,672" +"23,82348","0,206217","1838,297" +"23,8779","0,166361","1834,923" +"23,92232","0,12495","1831,548" +"23,95674","0,084107","1828,173" +"23,98116","0,046185","1824,798" +"23,99558","0,013978","1821,423" \ No newline at end of file diff --git a/src/Multilayer_Perceptron/Functions.py b/src/Multilayer_Perceptron/Functions.py new file mode 100644 index 0000000..b09eb1e --- /dev/null +++ b/src/Multilayer_Perceptron/Functions.py @@ -0,0 +1,136 @@ +""" +This file contains the functions used by the 'Main' file to convert the Python- +generated neural network into the 'structured text' language of ABB's 800xA +software. + +A description of the functionality and parameters of each function is provided +within the function itself. +""" + +def network_dictionary(network_file): + """ + This function creates a dictionary with the information from the neural + network generated by scikit-learn. + Input parameters: + network_file = Name of the file from which the information will be + extracted. + Output parameters: + neural_network = Dictionary containing all the information from the + network that may be useful in the conversion; + layers = Dictionary containing information about each layer of the + network. + """ + neural_network = {'Layers': []} + with open(network_file, 'r') as file: + layers = [] + layer = None + for line in file: + line = line.strip() + if line.startswith("Number of layers:"): + neural_network['Number of layers'] = int(line.split(":")[1].strip()) + elif line.startswith("Layer"): + if layer: + layers.append(layer) + layer = {} + layer['Neurons'] = [] + layer['Biases'] = {} + elif line.startswith("Neuron"): + neuron = line.split(":") + value = int(neuron[0].split()[-1]) + layer['Neurons'].append({'Neuron': value, 'Weights': {}}) + elif line.startswith("Weight from neuron"): + parts = line.split(":") + neuron = int(parts[0].split()[-1]) + weight = float(parts[1].strip()) + layer['Neurons'][-1]['Weights'][f'Weight from neuron {neuron}'] = weight + elif line.startswith("Bias from neuron"): + parts = line.split(":") + neuron = int(parts[0].split()[-1]) + bias = float(parts[1].strip()) + layer['Biases'][f'Bias from neuron {neuron}'] = bias + if layer: + layers.append(layer) + + neural_network['Layers'] = layers + return neural_network, layers + +######## +def write_file(layers, sizes_vector, input_vector, destination_file, neural_network, activation_function, out_activation_function): + """ + This function analyzes the parameters and translates the network into a + format compatible with the software. + Input parameters: + layers = Dictionary containing the information for each layer of the + network; + sizes_vector = Vector containing indices with the quantity of neurons + that each layer possesses; + input_vector = Vector containing the input variables; + destination_file = Name of the file where the substitutions will be made; + neural_network = Dictionary containing all the useful information of the + network; + activation_function = Overall activation function of the network; + out_activation_function = Activation function of the output layer. + Output parameters: + search_vector = Vector containing the names of the input variables for + each neuron; + biases_vector = Vector containing the biases to be added to the file; + output_vector = Vector containing the names of the output variables for + each neuron. + + """ + search_vector = []; biases_vector = []; output_vector = []; + for i, layer in enumerate(neural_network['Layers']): + if i < len(neural_network['Layers']): + layer = layers[i] + with open(destination_file, 'a') as file: + if i == len(neural_network['Layers']) - 1: + file.write('\n(*Input and output information of neurons in the output layer*)\n\n') + file.write('(## Calculation of neuron inputs ##)\n\n') + else: + file.write(f'\n(*Input and output information of neurons in the hidden layer {i+1}*)\n\n') + file.write('(## Calculation of neuron input(s) ##)\n') + neurons = layer['Neurons']; biases = layer['Biases'] + new_vector = [0] * sizes_vector[i] + for x in range(len(new_vector)): + for j, neuron in enumerate(neurons): + if j == x: + weight_neurons = neuron['Weights'] + for weight_key, weight_value in weight_neurons.items(): + number_neurons = int(weight_key.split()[-1]) + weight_value = f'{weight_value:.15f}' + with open(destination_file, 'a') as file: + if i == len(neural_network['Layers']) - 1 and number_neurons == 0: + file.write(f'N{i}{number_neurons} := ({input_vector[number_neurons]} * {weight_value}') + elif number_neurons == 0: + file.write(f'\nN{i}{x} := ({input_vector[number_neurons]} * {weight_value}') + else: + file.write(f' + {input_vector[number_neurons]} * {weight_value}') + key = f'N{i}{x} ' + if key not in search_vector: + search_vector.append(key) + with open(destination_file, 'a') as file: + file.write('\n\n(## Output of the neuron(s) - Application of the activation function ##) \n\n') + for bias_key, bias_value in biases.items(): + biases_vector.append(bias_value) + with open(destination_file, 'a') as file: + if i == len(layers) - 1: + activation = out_activation_function + else: + activation = activation_function + input_vector.clear() + for z in range(len(new_vector)): + with open(destination_file, 'a') as file: + if activation == 'relu': + file.write(f'N{i}{z}out := Max(0, N{i}{z});\n') + elif activation == 'tanh': + file.write(f'N{i}{z}out := (exp(N{i}{z}) - exp(-N{i}{z})) / (exp(N{i}{z}) + exp(-N{i}{z}));\n') + elif activation == 'logistic': + file.write(f'N{i}{z}out := 1 / (1 + exp(-N{i}{z}));\n') + elif activation == 'identity': + file.write(f'N{i}{z}out := N{i}{z};\n') + input_vector.append(f'N{i}{z}out') + output_vector.append(f'N{i}{z}out') + return search_vector, biases_vector, output_vector + + + \ No newline at end of file diff --git a/src/Multilayer_Perceptron/Main.py b/src/Multilayer_Perceptron/Main.py new file mode 100644 index 0000000..f91c1dd --- /dev/null +++ b/src/Multilayer_Perceptron/Main.py @@ -0,0 +1,177 @@ +""" +This file performs the conversion of a neural network structure (classification +or regression) generated in Python to a version suitable for the 'structured text' +language used in ABB's 800xA programming software. The purpose is to streamline +the work of engineers in implementing neural networks in an industrial environment. + +This file was designed considering the syntax of neural networks generated in +Python using the 'scikit-learn' library, which include multiple neurons in the +input layer, multiple hidden layers with multiple neurons and one neuron in the +output layer. Therefore, neural networks that do not meet these requirements +may not be correctly converted. + +A brief description of the code's operation: + +A .txt file containing information about the generated neural network should be +saved in the same directory as this file. To generate the .txt file with such +information, we suggest copying the code below to the end of the user-created +file used to generate the neural network. + + --------------------------------------------------------------------------- + with open('filename.txt', 'w') as file: + num_layers = len(mlp.hidden_layer_sizes) + 2 + file.write(f"Number of layers: {num_layers}\n") + file.write(f"Activation Function: {activation_function}\n") + file.write(f"Activation Function of the Output Layer: {mlp.out_activation_}\n") + file.write('\n') + file.write("Input layer:\n") + for i, variable in enumerate(X_train.columns): + file.write(f" Input Neuron {i + 1}: {variable}\n") + file.write('\n') + for j, (layer, biases) in enumerate(zip(mlp.coefs_, mlp.intercepts_)): + file.write(f"Layer {j + 1} - Neurons: {layer.shape[1]}\n") + file.write("Weights:\n") + for neuron_dest in range(layer.shape[1]): + file.write(f"Neuron {neuron_dest}:\n") + for neuron_src, weight in enumerate(layer[:, neuron_dest]): + file.write(f" Weight from neuron {neuron_src}: {weight:.2f}\n") + file.write("Biases:\n") + for neuron, bias in enumerate(biases): + file.write(f" Bias from neuron {neuron}: {bias:.2f}\n") + file.write("\n") + + NOTE: + + - Replace 'filename' with the desired name + - Replace 'mlp' with the variable name containing the neural network. + --------------------------------------------------------------------------- + When initiating this code, the user will need to provide the following + information: + 1- Name of the .txt file containing the information of the created neural + network; + 3 - Name of the output variable to be written in the converted neural + network. + + After entering the information, this code will generate a .txt file in + the same directory as this code, resulting in a neural network that + maintains the same functionality as the original neural network but with + syntax adherent to the 'structured text' language used by the ABB 800xA + software. + + Additionally, another file ('table.txt') is generated, containing the + variables and parameters used in the code, along with information such + as 'Data type,' 'Direction,' 'FD Port,' and 'Attributes'. + + + In this way, it is possible to copy the content of the generated .txt file + by this code and paste it directly into the 800xA software, with only the + necessary adjustments, such as declaring variables in the 800xA software. + +""" +import re +from Functions import network_dictionary, write_file + +# -------- Input neural network information -------- + +# -------- Validation of the existence of the .txt file in the folder +while True: + original_name = input('Source file name: ') + network_file = original_name + '.txt' + + try: + # -------- Creating table file and destination file-------- + file_table = original_name + '_table' + '.txt' + destination_file = original_name + '_800xA' + '.txt' + with open(network_file, 'rb') as original: + with open(destination_file, 'wb') as destiny: + destiny.write(original.read()) + break + + except FileNotFoundError: + print(f"ATTENTION!\n The file {network_file} does not exist in this folder. Please enter the original file name again.\n") + +# ------- Exporting the neural network information from the dictionary ------- + +neural_network, layers = network_dictionary(network_file) +with open(destination_file, 'w') as file: + file.write('(*The variables are in the format Nij, where i denotes the layer number, and j denotes the neuron number.*)\n') + +# ------- Checking the number of input variables, the activation function of the overall network and the activation function of the output layer ------- + +with open (network_file, 'r') as file: + lines = file.readlines() + for line in lines: + activation_function = lines[1].split(":")[1].strip() + out_activation_function = lines[2].split(":")[1].strip() + +## ------- Building the parameter table ------- + +input_vector = [] +with open(file_table, 'w') as file: + file.write('Parameters:\n') + with open(network_file, 'r') as file_in: + lines = file_in.readlines() + for line in lines: + if line.strip().startswith('Input Neuron'): + parts = line.split(':') + if len(parts) > 1: + inputs = parts[1].strip() + input_vector.append(inputs) + line = f'{inputs}\treal\t\tin\tyes\n' + file.write(line) + while True: + output = input("Enter the output variable: ") + if output not in input_vector: + break + else: + print("ERROR: The output variable should be different from the input variables. Please provide a different variable.") + file.write(f'{output}\treal\t\tout\tyes\n') + +num_inputs = len(input_vector) +# ------- Creating a vector with indices containing the number of neurons in each layer ------- + +sizes_vector = [] +for i in range(neural_network['Number of layers'] - 1): + layer = layers[i] + neurons = layer['Neurons'] + sizes_vector.append(len(neurons)) + +# ------- Writing the information to the file ------- + +search_vector, biases_vector, output_vector = write_file(layers, sizes_vector, input_vector, destination_file, neural_network, activation_function, out_activation_function) + +# ------- Adding the biases to the file ------- + +with open(destination_file, 'r') as read_file: + lines = read_file.readlines() +for index, bias_value in zip(search_vector, biases_vector): + for i, line in enumerate(lines): + if index in line: + lines[i] = f"{line.strip()}) + {bias_value}; \n" +with open(destination_file, 'w') as file: + file.writelines(lines) + +## ------- Building the variable table ------- + +with open(file_table, 'a') as file: + file.write('\nVariables:\n') + for variable, out in zip(search_vector, output_vector): + line = f'{variable.strip()}\treal\tretain\n' + file.write(line) + out_line = f'{out.strip()}\treal\tretain\n' + file.write(out_line) +with open(file_table, 'r') as file: + lines = file.readlines() +with open(file_table, 'w') as file: + file.writelines(lines[:-1]) + +# ------- Inserting the chosen name for the output variable into the file ------- + +with open(destination_file, 'r') as file: + lines = file.readlines() +default = re.compile(rf'^{re.escape(output_vector[-1])}\b') +for i, line in enumerate(lines): + if default.match(line): + lines[i] = default.sub(output, line) +with open(destination_file, 'w') as file: + file.writelines(lines) \ No newline at end of file