amirhosseinkarami commited on
Commit
bae498f
1 Parent(s): 1139920

Add code files

Browse files
Files changed (11) hide show
  1. CompareRegressors.py +227 -0
  2. DESolver.py +64 -0
  3. DataUtils.py +801 -0
  4. FeynmanEqns.txt +19 -0
  5. LearnRules.py +146 -0
  6. LearnTriangles.py +252 -0
  7. MLP_Model.py +239 -0
  8. RegressorTest.py +115 -0
  9. Settings.py +277 -0
  10. SymbolicFunctionLearner.py +1449 -0
  11. gp_model.py +163 -0
CompareRegressors.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 786/110
2
+
3
+ import os
4
+ import sys
5
+ import time
6
+
7
+ import matplotlib.pyplot as plt
8
+ import numpy as np
9
+
10
+ import DataUtils
11
+ import Settings as settings
12
+ from DataUtils import generate_random_eqn, multidim_dataset_from_eqn_list
13
+ from DataUtils import simple_eqn_to_str
14
+ from MLP_Model import MLP_Model
15
+ # from models.smtree_model import SMTree_Model
16
+ # from models.smftree_model import SMFTree_Model
17
+ # from models.smfftree_model import SMFFTree_Model
18
+ # from models.addoptree_model import AddOpTree_Model
19
+ # from models.crtree_model import CRTree_Model
20
+ # from models.sptree_model import SpTree_Model
21
+ # from models.lbl_model import LBLTree_Model
22
+ from SymbolicFunctionLearner import SFL
23
+ # from models.mcts_model import MCTS_Model
24
+ from gp_model import Genetic_Model
25
+
26
+ """ Test Hyperparameters """
27
+ num_eqns_to_create = 150
28
+ num_training = 1000
29
+ num_valid = 1000
30
+ num_test = 1000
31
+ allowable_ops = settings.function_set.copy()
32
+ num_vars = 1 # 10
33
+ num_max_levels = 3 # 4
34
+
35
+ settings.n_tree_layers = num_max_levels
36
+ settings.num_features = num_vars
37
+ settings.show_output = False
38
+ settings.keep_logs = False
39
+ settings.mode = "sr"
40
+
41
+ show_found_eqns = True
42
+
43
+ use_constants_in_eqns = True
44
+
45
+ if not os.path.exists('images'):
46
+ os.makedirs('images')
47
+
48
+
49
+ def plot_all_models(eqn_str, eqn_number, all_models, this_train_x, this_train_y,
50
+ this_test_x, this_test_y):
51
+ plt.figure()
52
+ plt.title('Compare models: {}'.format(eqn_str))
53
+
54
+ min_y = np.min(this_test_y)
55
+ max_y = np.max(this_test_y)
56
+ y_range = max_y - min_y
57
+
58
+ plt.scatter(this_train_x, this_train_y, color='xkcd:dark pink',
59
+ marker='o', s=100, label='Training set')
60
+
61
+ plt.scatter(this_test_x, this_test_y, color='gray', alpha=0.5, marker='.', label='Ground truth')
62
+
63
+ for i in range(len(all_models)):
64
+ this_model = all_models[i]
65
+ test_hat_y = this_model.predict(this_test_x)
66
+ plt.scatter(this_test_x,
67
+ test_hat_y, alpha=0.7, marker='.', label='{}'.format(this_model.name))
68
+
69
+ for xc in settings.train_scope:
70
+ plt.axvline(x=xc, color='k', linestyle='dashed', linewidth=2)
71
+
72
+ plt.ylim([min_y - 0.5 * y_range, max_y + 0.5 * y_range])
73
+
74
+ plt.legend()
75
+ plt.savefig("images/eqn_{}.png".format(eqn_number))
76
+ plt.close()
77
+
78
+
79
+ models_to_test = []
80
+ models_to_test.append(Genetic_Model)
81
+ models_to_test.append(MLP_Model)
82
+ # models_to_test.append(Tree_Model)
83
+
84
+ models_to_test.append(SFL)
85
+ # models_to_test.append(SMTree_Model)
86
+ # models_to_test.append(SMFTree_Model)
87
+ # models_to_test.append(SMFFTree_Model)
88
+ # models_to_test.append(AddOpTree_Model)
89
+
90
+ # models_to_test.append(SpTree_Model)
91
+
92
+
93
+ lists_of_error_scores = []
94
+ lists_of_iter_times = []
95
+ all_models = []
96
+ for model_type in models_to_test:
97
+ all_models.append(model_type())
98
+ lists_of_error_scores.append([])
99
+ lists_of_iter_times.append([])
100
+
101
+ # all_models.append(SpTree_Model(use_scopers=True))
102
+ # lists_of_error_scores.append([])
103
+ # lists_of_iter_times.append([])
104
+
105
+ seen_eqns = []
106
+ winning_entries = []
107
+ valid_err = 0
108
+
109
+ print("Starting program.")
110
+ print(settings.num_features)
111
+
112
+ start_time = time.time()
113
+
114
+ for eqn_n in range(1, num_eqns_to_create + 1):
115
+ print("----------------")
116
+ # Create some random equation
117
+ current_eqn_as_list = generate_random_eqn(allowable_ops, num_vars, num_max_levels,
118
+ allow_constants=use_constants_in_eqns)
119
+ current_eqn_as_str = simple_eqn_to_str(current_eqn_as_list)
120
+
121
+ # should be a new equation
122
+ while current_eqn_as_str in seen_eqns:
123
+ current_eqn_as_list = generate_random_eqn(allowable_ops, num_vars, num_max_levels,
124
+ allow_constants=use_constants_in_eqns)
125
+ current_eqn_as_str = simple_eqn_to_str(current_eqn_as_list)
126
+ seen_eqns.append(current_eqn_as_str)
127
+
128
+ print(current_eqn_as_list)
129
+ print("Random equation {} of {}".format(eqn_n, num_eqns_to_create))
130
+ print("True function: {}\n".format(current_eqn_as_str))
131
+ with open("images/compare_test_output.txt", "a") as output_file:
132
+ output_file.write("\n{}\nTrue equation:\n{}\n".format(eqn_n, current_eqn_as_str))
133
+
134
+ # Create a dataset with that equation
135
+ train_data_x, train_data_y = multidim_dataset_from_eqn_list(current_eqn_as_list, num_training, n_vars=num_vars)
136
+ test_data_x, test_data_y = multidim_dataset_from_eqn_list(current_eqn_as_list, num_test, n_vars=num_vars,
137
+ min_x=settings.test_scope[0],
138
+ max_x=settings.test_scope[1])
139
+
140
+ # train_data_x, train_data_y = create_dataset_from_eqn_list(current_eqn_as_list, num_vars, num_training,
141
+ # settings.train_scope[0], settings.train_scope[1])
142
+ # test_data_x, test_data_y = create_dataset_from_eqn_list(current_eqn_as_list, num_vars, num_test,
143
+ # settings.test_scope[0], settings.test_scope[1])
144
+
145
+ for model_i in range(len(all_models)):
146
+ model = all_models[model_i]
147
+ model.reset()
148
+ itertime_start = time.time()
149
+ # if False: # model_i >= len(all_models) - 2:
150
+ # model.repeat_train(train_data_x, train_data_y)
151
+ # else:
152
+ model_eqn, _, best_err = model.repeat_train(train_data_x, train_data_y,
153
+ test_x=test_data_x, test_y=test_data_y,
154
+ verbose=False)
155
+ if show_found_eqns:
156
+ print("{} function: {}".format(model.name, model_eqn)[:550])
157
+
158
+ # Test model on that equation
159
+ # test_err = model.test(test_data_x, test_data_y)
160
+ test_err = max(np.exp(-10), best_err) # data_utils.test_from_formula(model_eqn, test_data_x, test_data_y)
161
+ print(" ---> {} Test Error: {:.5f}".format(model.short_name, test_err))
162
+ lists_of_error_scores[model_i].extend([test_err])
163
+ lists_of_iter_times[model_i].append(time.time() - itertime_start)
164
+ sys.stdout.flush()
165
+
166
+ # y_gold_list = list(model.sess.run(model.y_gold,
167
+ # feed_dict={model.data_x: np.reshape(test_data_x[:4][:], [-1, num_vars]),
168
+ # model.data_y: np.reshape(test_data_y[:4][:], [-1, 1]),
169
+ # model.var_random_u: model.var_random_selector,
170
+ # model.op_random_u: model.op_random_selector}).reshape(1, -1)[0])
171
+ # y_hat_list2 = data_utils.predict_from_formula(model.get_simple_formula(digits=4), test_data_x[:4][:])
172
+ #
173
+ # print('Performance on sample validation data:')
174
+ # for feature_i in range(model.n_input_variables):
175
+ # print('x{}: '.format(feature_i + 1),
176
+ # ['{:7.4f}'.format(yyy[feature_i]) for yyy in test_data_x[:4][:]])
177
+ # print("-----------------------------------------------------")
178
+ # print('y_gold: ', ['{:7.4f}'.format(yyy) for yyy in y_gold_list])
179
+ # print('y_hat2: ', ['{:7.4f}'.format(yyy) for yyy in y_hat_list2])
180
+
181
+ if test_err < 0.035:
182
+ winning_entries.append("{} - {}".format(current_eqn_as_str, model.short_name))
183
+
184
+ with open("images/compare_test_output.txt", "a") as output_file:
185
+ output_file.write("{}: {}\n{}\n".format(model.short_name, test_err, model_eqn))
186
+
187
+ print()
188
+
189
+ DataUtils.plot_hist_of_errors(lists_of_error_scores, all_models, eqn_n)
190
+
191
+ # todo: something is wrong with this function!!
192
+ # todo: it plots the model as is (after last iter), not at best iter, of repeat_train
193
+ # DataUtils.plot_all_models_predicted_actual(all_models, test_data_x, test_data_y,
194
+ # set_name="Eqn {}: {}".format(eqn_n, current_eqn_as_str),
195
+ # fig_name="eqn_{}".format(eqn_n))
196
+
197
+ plt.figure()
198
+ x_axis = [i + 1 for i in range(eqn_n)]
199
+ for iter_times_i in range(len(lists_of_iter_times)):
200
+ plt.plot(x_axis, lists_of_iter_times[iter_times_i], label=all_models[iter_times_i].short_name)
201
+ plt.xlabel("Iteration")
202
+ plt.ylabel("Running time")
203
+ plt.legend()
204
+ plt.savefig("images/time_curve.png")
205
+ plt.close()
206
+
207
+ # if num_vars == 1:
208
+ # plot_all_models(current_eqn_as_str, eqn_n, all_models,
209
+ # train_data_x, train_data_y,
210
+ # test_data_x, test_data_y)
211
+
212
+ running_time = time.time() - start_time
213
+ print("Done. Took {} seconds.\n".format(running_time))
214
+ #
215
+ # plt.figure()
216
+ # plt.hist([list_of_error_scores_GP, list_of_error_scores_MLP, list_of_error_scores_Tree], label=['GP', 'MLP', 'Tree'])
217
+ # plt.legend(loc='upper right')
218
+ # plt.show()
219
+ #
220
+ # plt.figure()
221
+ # plt.hist(list_of_error_scores_GP, edgecolor='k', linewidth=1.2)
222
+ # plt.show()
223
+ #
224
+ # plt.figure()
225
+ # plt.hist(list_of_error_scores_GP, cumulative=True)
226
+ # plt.show()
227
+ #
DESolver.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """""""""""""""""""""""""""""""""
2
+ This file is for running.
3
+ Do not modify this file.
4
+
5
+ For running: DiffEqnSolver.py
6
+ For modifying: settings.py
7
+ """""""""""""""""""""""""""""""""
8
+
9
+ import os
10
+ import time
11
+
12
+ import DataUtils
13
+ import Settings as settings
14
+ from SymbolicFunctionLearner import SFL
15
+
16
+ settings.mode = "de"
17
+
18
+ current_model = SFL()
19
+ if not os.path.exists('images'):
20
+ os.makedirs('images')
21
+
22
+ print('\nBeginning experiment: {}'.format(current_model.name))
23
+
24
+ print("{} tree layers.".format(settings.n_tree_layers))
25
+ print("{} features of {} component(s) each.".format(settings.num_features, settings.num_dims_per_feature))
26
+ print("{} components in output.".format(settings.n_dims_in_output))
27
+ print("{} operators: {}.".format(len(current_model.function_set),
28
+ current_model.function_set))
29
+
30
+ train_errors = []
31
+ valid_errors = []
32
+ test_errors = []
33
+ true_eqns = []
34
+
35
+ train_X = DataUtils.generate_data(settings.train_N, n_vars=current_model.n_input_variables,
36
+ avoid_zero=settings.avoid_zero)
37
+ valid_X = DataUtils.generate_data(settings.train_N, n_vars=current_model.n_input_variables,
38
+ avoid_zero=settings.avoid_zero)
39
+ test_X = DataUtils.generate_data(settings.test_N, n_vars=current_model.n_input_variables,
40
+ min_x=settings.test_scope[0],
41
+ max_x=settings.test_scope[1])
42
+
43
+ print("\n========================")
44
+ print("Starting Solver.")
45
+ print("==========================\n")
46
+
47
+ # Train the model from scratch several times, keeping the best one.
48
+ start_time = time.time()
49
+ best_model, best_iter, best_err = current_model.repeat_train(train_X,
50
+ num_repeats=settings.num_train_repeat_processes,
51
+ test_x=test_X)
52
+ running_time = time.time() - start_time
53
+
54
+ print("best_model: {}".format(best_model))
55
+ print("----------------------")
56
+ print("Finished DE. Took {:.2f} minutes.\n".format(running_time / 60))
57
+
58
+
59
+ print("Final solution found at attempt {}:".format(best_iter))
60
+ print("y = {}".format(best_model))
61
+ print("Test error: {}".format(best_err))
62
+ if best_err < 0.02:
63
+ print("Attained error less than 0.02 - great!")
64
+ print()
DataUtils.py ADDED
@@ -0,0 +1,801 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """""""""""""""""""""""""""""""""
2
+ Do not run or modify this file.
3
+
4
+ For running: DiffEqnSolver.py
5
+ For modifying: settings.py
6
+ """""""""""""""""""""""""""""""""
7
+
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+ import sympy
11
+ import tensorflow as tf
12
+ from matplotlib import cm
13
+ from sympy import expand, sympify, lambdify
14
+
15
+ import Settings
16
+
17
+
18
+ def safe_abs(x):
19
+ return np.sqrt(x * x + Settings.eps)
20
+
21
+
22
+ def safe_div(x, y):
23
+ return np.sign(y) * x / safe_abs(y)
24
+
25
+
26
+ def tf_diff_abs(x):
27
+ return tf.sqrt(tf.square(x) + Settings.eps)
28
+
29
+
30
+ def tf_diff_sqrt(x):
31
+ return tf.sqrt(tf_diff_abs(x))
32
+
33
+
34
+ def tf_diff_log(x):
35
+ return tf.math.log(tf_diff_abs(x))
36
+
37
+
38
+ def our_tanh(x, factor=1000):
39
+ return factor * tf.tanh(x / factor)
40
+
41
+
42
+ def spike(x):
43
+ return 1.0 / (1 + 200 * tf.square(x))
44
+ # return tf.math.exp(-10 * tf.square(x))
45
+
46
+
47
+ def true_function(input_x):
48
+ return predict_from_formula(Settings.true_eqn, input_x)
49
+
50
+
51
+ def is_float(value):
52
+ try:
53
+ float(value)
54
+ return True
55
+ except ValueError:
56
+ return False
57
+
58
+
59
+ # Function to generate random equation as operator/input list
60
+ # Variables are numbered 1 ... n, and 0 does not appear
61
+ # Constants appear as [float] e.g [3.14]
62
+ def generate_random_eqn_two_list(op_list, n_vars, n_levels, allow_constants=True):
63
+ eqn_ops = list(np.random.choice(op_list, size=int(2 ** n_levels) - 1, replace=True))
64
+
65
+ if allow_constants:
66
+ eqn_vars = list(np.random.choice(range(1, max(int(n_vars * 1.6), n_vars + 2)),
67
+ size=int(2 ** n_levels), replace=True))
68
+ for i in range(len(eqn_vars)):
69
+ if eqn_vars[i] >= n_vars + 1:
70
+ eqn_vars[i] = [np.random.uniform(Settings.test_scope[0], Settings.test_scope[1])]
71
+ else:
72
+ eqn_vars = list(np.random.choice(range(1, 1 + n_vars), size=int(2 ** n_levels), replace=True))
73
+ return [eqn_ops, eqn_vars]
74
+
75
+
76
+ # Function to generate random equation as operator/input list and weight/bias list
77
+ # Variables are numbered 1 ... n, and 0 does not appear
78
+ # Constants appear in weight and bias lists.
79
+ # const_ratio determines how many weights are not 1, and how many biases are not 0
80
+ def generate_random_eqn(op_list, n_vars, n_levels, allow_constants=True, const_ratio=0.8):
81
+ eqn_ops = list(np.random.choice(op_list, size=int(2 ** n_levels) - 1, replace=True))
82
+ eqn_vars = list(np.random.choice(range(1, (n_vars + 1)), size=int(2 ** n_levels), replace=True))
83
+ max_bound = max(np.abs(Settings.test_scope[0]), np.abs(Settings.test_scope[1]))
84
+ eqn_weights = list(np.random.uniform(-1 * max_bound, max_bound, size=len(eqn_vars)))
85
+ eqn_biases = list(np.random.uniform(-1 * max_bound, max_bound, size=len(eqn_vars)))
86
+
87
+ if not allow_constants:
88
+ const_ratio = 0.0
89
+ random_const_chooser_w = np.random.uniform(0, 1, len(eqn_weights))
90
+ random_const_chooser_b = np.random.uniform(0, 1, len(eqn_biases))
91
+
92
+ for i in range(len(eqn_weights)):
93
+ if random_const_chooser_w[i] >= const_ratio:
94
+ eqn_weights[i] = 1
95
+ if random_const_chooser_b[i] >= const_ratio:
96
+ eqn_biases[i] = 0
97
+
98
+ return [eqn_ops, eqn_vars, eqn_weights, eqn_biases]
99
+
100
+
101
+ # Function to create a multidim input data set given an operator/input list
102
+ def generate_data(n_points, n_vars=Settings.num_features,
103
+ n_input_dims=Settings.num_dims_per_feature,
104
+ min_x=Settings.train_scope[0], max_x=Settings.train_scope[1],
105
+ avoid_zero=False):
106
+ if not avoid_zero:
107
+ x_data = [np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars]) for _ in range(n_points)]
108
+ else:
109
+ x_data = []
110
+ for _ in range(n_points):
111
+ candidate = np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars])
112
+ while np.linalg.norm(candidate) < 0.1:
113
+ candidate = np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars])
114
+ x_data.append(candidate)
115
+ return np.array(x_data)
116
+
117
+
118
+ # Function to create a data set given an operator/input list
119
+ def create_dataset_from_eqn_list(eqn_as_list, n_vars, n_points, min_x, max_x):
120
+ x_data = [list(np.random.uniform(min_x, max_x, n_vars)) for _ in range(n_points)]
121
+ y_data = [evaluate_eqn_list_on_datum(eqn_as_list, x_data_i) + np.random.normal(0, 0.05) for x_data_i in x_data]
122
+ return [np.array(x_data), np.array(y_data)]
123
+
124
+
125
+ # Function to create a multidim data set given an operator/input list
126
+ def multidim_dataset_from_eqn_list(eqn_as_list, n_points,
127
+ n_vars=Settings.num_features,
128
+ n_input_dims=Settings.num_dims_per_feature,
129
+ n_output_dims=Settings.n_dims_in_output,
130
+ min_x=Settings.train_scope[0], max_x=Settings.train_scope[1],
131
+ avoid_zero=False):
132
+ if not avoid_zero:
133
+ x_data = [np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars]) for _ in range(n_points)]
134
+ else:
135
+ x_data = []
136
+ for _ in range(n_points):
137
+ candidate = np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars])
138
+ while np.linalg.norm(candidate) < 0.1:
139
+ candidate = np.random.uniform(min_x, max_x, size=[n_input_dims, n_vars])
140
+ x_data.append(candidate)
141
+ y_data = [evaluate_eqn_list_on_multidim_datum(eqn_as_list, x_data_i) # + np.random.normal(0, 0.05)
142
+ for x_data_i in x_data]
143
+ if n_output_dims == 1:
144
+ y_data = [np.mean(old_y) for old_y in y_data]
145
+ return [np.array(x_data), np.reshape(np.array(y_data), [n_points, n_output_dims, 1])]
146
+
147
+
148
+ def make_y_multi_safe(old_y, n_dims_per_input_var=1, n_dims_in_output=1):
149
+ if isinstance(old_y, list):
150
+ new_y = np.array(old_y)
151
+ new_y.reshape([-1, n_dims_in_output, 1])
152
+ else:
153
+ new_y = old_y.copy()
154
+ if len(new_y.shape) == 1:
155
+ assert (n_dims_in_output == 1)
156
+ new_y = [[[y_value] for _ in range(n_dims_per_input_var)] for y_value in new_y]
157
+ new_y = np.array(new_y)
158
+ elif len(new_y.shape) == 2:
159
+ assert (n_dims_in_output == 1)
160
+ new_y = [[y_value for _ in range(n_dims_per_input_var)] for y_value in new_y]
161
+ new_y = np.array(new_y)
162
+ elif new_y.shape[1] < n_dims_per_input_var:
163
+ assert (n_dims_in_output == 1)
164
+ new_y = [[y_value[0] for _ in range(n_dims_per_input_var)] for y_value in new_y]
165
+ new_y = np.array(new_y)
166
+ return new_y
167
+
168
+
169
+ # Function to evaluate equation (in two-list format) on a data point
170
+ def evaluate_eqn_list_on_datum_two_list(eqn_as_list, input_x):
171
+ eqn_ops = eqn_as_list[0]
172
+ eqn_vars = eqn_as_list[1]
173
+ current_op = eqn_ops[0]
174
+
175
+ if len(eqn_ops) == 1:
176
+ if type(eqn_vars[0]) is list:
177
+ left_side = eqn_vars[0][0]
178
+ else:
179
+ left_side = input_x[eqn_vars[0] - 1]
180
+ if type(eqn_vars[1]) is list:
181
+ right_side = eqn_vars[1][0]
182
+ else:
183
+ right_side = input_x[eqn_vars[1] - 1]
184
+
185
+ else:
186
+ split_point = int((len(eqn_ops) + 1) / 2)
187
+ left_ops = eqn_ops[1:split_point]
188
+ right_ops = eqn_ops[split_point:]
189
+
190
+ left_vars = eqn_vars[:split_point]
191
+ right_vars = eqn_vars[split_point:]
192
+
193
+ left_side = evaluate_eqn_list_on_datum_two_list([left_ops, left_vars], input_x)
194
+ right_side = evaluate_eqn_list_on_datum_two_list([right_ops, right_vars], input_x)
195
+
196
+ if current_op == 'id':
197
+ return left_side
198
+
199
+ if current_op == 'sqrt':
200
+ return np.sqrt(np.abs(left_side))
201
+
202
+ if current_op == 'log':
203
+ return np.log(np.sqrt(left_side * left_side + 1e-10))
204
+
205
+ if current_op == 'sin':
206
+ return np.sin(left_side)
207
+
208
+ if current_op == 'exp':
209
+ return np.exp(left_side)
210
+
211
+ if current_op == 'add':
212
+ return left_side + right_side
213
+
214
+ if current_op == 'mul':
215
+ return left_side * right_side
216
+
217
+ if current_op == 'sub':
218
+ return left_side - right_side
219
+
220
+ if current_op == 'div':
221
+ return safe_div(left_side, right_side)
222
+
223
+ return None
224
+
225
+
226
+ # Function to evaluate equation (in list format) on a data point
227
+ def evaluate_eqn_list_on_datum(eqn_as_list, input_x):
228
+ eqn_ops = eqn_as_list[0]
229
+ eqn_vars = eqn_as_list[1]
230
+ eqn_weights = eqn_as_list[2]
231
+ eqn_biases = eqn_as_list[3]
232
+ current_op = eqn_ops[0]
233
+
234
+ if len(eqn_ops) == 1:
235
+ left_side = eqn_weights[0] * input_x[eqn_vars[0] - 1] + eqn_biases[0]
236
+ right_side = eqn_weights[1] * input_x[eqn_vars[1] - 1] + eqn_biases[1]
237
+
238
+ else:
239
+ split_point = int((len(eqn_ops) + 1) / 2)
240
+ left_ops = eqn_ops[1:split_point]
241
+ right_ops = eqn_ops[split_point:]
242
+
243
+ left_vars = eqn_vars[:split_point]
244
+ right_vars = eqn_vars[split_point:]
245
+
246
+ left_weights = eqn_weights[:split_point]
247
+ right_weights = eqn_weights[split_point:]
248
+
249
+ left_biases = eqn_biases[:split_point]
250
+ right_biases = eqn_biases[split_point:]
251
+
252
+ left_side = evaluate_eqn_list_on_datum([left_ops, left_vars, left_weights, left_biases], input_x)
253
+ right_side = evaluate_eqn_list_on_datum([right_ops, right_vars, right_weights, right_biases], input_x)
254
+
255
+ if current_op == 'id':
256
+ return left_side
257
+
258
+ if current_op == 'sqrt':
259
+ return np.sqrt(np.abs(left_side))
260
+
261
+ if current_op == 'log':
262
+ return np.log(np.sqrt(left_side * left_side + 1e-10))
263
+
264
+ if current_op == 'sin':
265
+ return np.sin(left_side)
266
+
267
+ if current_op == 'exp':
268
+ return np.exp(left_side)
269
+
270
+ if current_op == 'add':
271
+ return left_side + right_side
272
+
273
+ if current_op == 'mul':
274
+ return left_side * right_side
275
+
276
+ if current_op == 'sub':
277
+ return left_side - right_side
278
+
279
+ if current_op == 'div':
280
+ return safe_div(left_side, right_side)
281
+
282
+ return None
283
+
284
+
285
+ # Function to evaluate equation (in two-list format) on a data point
286
+ def evaluate_eqn_list_on_multidim_datum_two_list(eqn_as_list, input_x):
287
+ eqn_ops = eqn_as_list[0]
288
+ eqn_vars = eqn_as_list[1]
289
+ current_op = eqn_ops[0]
290
+
291
+ if len(eqn_ops) == 1:
292
+ if type(eqn_vars[0]) is list:
293
+ left_side = eqn_vars[0][0]
294
+ else:
295
+ left_side = input_x[:, eqn_vars[0] - 1]
296
+ if type(eqn_vars[1]) is list:
297
+ right_side = eqn_vars[1][0]
298
+ else:
299
+ right_side = input_x[:, eqn_vars[1] - 1]
300
+
301
+ else:
302
+ split_point = int((len(eqn_ops) + 1) / 2)
303
+ left_ops = eqn_ops[1:split_point]
304
+ right_ops = eqn_ops[split_point:]
305
+
306
+ left_vars = eqn_vars[:split_point]
307
+ right_vars = eqn_vars[split_point:]
308
+
309
+ left_side = evaluate_eqn_list_on_multidim_datum_two_list([left_ops, left_vars], input_x)
310
+ right_side = evaluate_eqn_list_on_multidim_datum_two_list([right_ops, right_vars], input_x)
311
+
312
+ if current_op == 'id':
313
+ return left_side
314
+
315
+ if current_op == 'sqrt':
316
+ return np.sqrt(np.abs(left_side))
317
+
318
+ if current_op == 'log':
319
+ return np.log(np.sqrt(left_side * left_side + 1e-10))
320
+
321
+ if current_op == 'sin':
322
+ return np.sin(left_side)
323
+
324
+ if current_op == 'exp':
325
+ return np.exp(left_side)
326
+
327
+ if current_op == 'add':
328
+ return left_side + right_side
329
+
330
+ if current_op == 'mul':
331
+ return left_side * right_side
332
+
333
+ if current_op == 'sub':
334
+ return left_side - right_side
335
+
336
+ if current_op == 'div':
337
+ return safe_div(left_side, right_side)
338
+ return None
339
+
340
+
341
+ # Function to evaluate equation (in list format) on a data point
342
+ def evaluate_eqn_list_on_multidim_datum(eqn_as_list, input_x):
343
+ eqn_ops = eqn_as_list[0]
344
+ eqn_vars = eqn_as_list[1]
345
+ eqn_weights = eqn_as_list[2]
346
+ eqn_biases = eqn_as_list[3]
347
+ current_op = eqn_ops[0]
348
+
349
+ if len(eqn_ops) == 1:
350
+ left_side = eqn_weights[0] * input_x[:, eqn_vars[0] - 1] + eqn_biases[0]
351
+ right_side = eqn_weights[1] * input_x[:, eqn_vars[1] - 1] + eqn_biases[1]
352
+
353
+ else:
354
+ split_point = int((len(eqn_ops) + 1) / 2)
355
+ left_ops = eqn_ops[1:split_point]
356
+ right_ops = eqn_ops[split_point:]
357
+
358
+ left_vars = eqn_vars[:split_point]
359
+ right_vars = eqn_vars[split_point:]
360
+
361
+ left_weights = eqn_weights[:split_point]
362
+ right_weights = eqn_weights[split_point:]
363
+
364
+ left_biases = eqn_biases[:split_point]
365
+ right_biases = eqn_biases[split_point:]
366
+
367
+ left_side = evaluate_eqn_list_on_multidim_datum([left_ops, left_vars, left_weights, left_biases], input_x)
368
+ right_side = evaluate_eqn_list_on_multidim_datum([right_ops, right_vars, right_weights, right_biases], input_x)
369
+
370
+ if current_op == 'id':
371
+ return left_side
372
+
373
+ if current_op == 'sqrt':
374
+ return np.sqrt(np.abs(left_side))
375
+
376
+ if current_op == 'log':
377
+ return np.log(np.sqrt(left_side * left_side + 1e-10))
378
+
379
+ if current_op == 'sin':
380
+ return np.sin(left_side)
381
+
382
+ if current_op == 'exp':
383
+ return np.exp(left_side)
384
+
385
+ if current_op == 'add':
386
+ return left_side + right_side
387
+
388
+ if current_op == 'mul':
389
+ return left_side * right_side
390
+
391
+ if current_op == 'sub':
392
+ return left_side - right_side
393
+
394
+ if current_op == 'div':
395
+ return safe_div(left_side, right_side)
396
+ return None
397
+
398
+
399
+
400
+ def choices_to_init_weight_matrix(choice_list, all_choices):
401
+ init_weight_matrix = np.zeros(shape=[len(choice_list), len(all_choices)])
402
+ for row in range(len(choice_list)):
403
+ if choice_list[row] in all_choices:
404
+ init_weight_matrix[row][all_choices.index(choice_list[row])] = Settings.init_weight_value
405
+ elif isinstance(choice_list[row], str) and "not" in choice_list[row] and choice_list[row].index("not") == 0 and \
406
+ choice_list[row][len("not"):] in all_choices:
407
+ init_weight_matrix[row][all_choices.index(choice_list[row][len("not"):])] = -100
408
+ return init_weight_matrix.T
409
+
410
+
411
+ def predict_from_formula(formula_str, x_values):
412
+ if Settings.num_features == 1:
413
+ x_variables = [["x"]]
414
+ else:
415
+ x_variables = [["x{}".format(var_i + 1) for var_i in range(Settings.num_features)]]
416
+ f = lambdify(x_variables, formula_str, 'numpy')
417
+ if isinstance(x_values, list):
418
+ return [f(x_values[row_i]) for row_i in range(len(x_values))]
419
+ elif len(x_values.shape) == 2:
420
+ return [f(x_values[row_i, :]) for row_i in range(x_values.shape[0])]
421
+ else:
422
+ return [f(x_values[row_i, :, :].reshape([-1, 1])) for row_i in range(x_values.shape[0])]
423
+
424
+
425
+ def leaves_up_from_dfs_order(orig_list, num_layers):
426
+ if num_layers <= 1:
427
+ return orig_list
428
+ index_list = [[i, i+1] for i in range(0, int(2**(num_layers-1)), 2)]
429
+
430
+ # print("start with: {}".format(index_list))
431
+ last_value=index_list[-1][-1]
432
+ while len(index_list) > 1:
433
+ new_index_list = []
434
+ for j in range(int(len(index_list) / 2)):
435
+ last_value += 1
436
+ new_list = [last_value]
437
+ new_list.extend(index_list[2*j])
438
+
439
+ last_value += 1
440
+ new_list.append(last_value)
441
+ new_list.extend(index_list[2*j+1])
442
+ new_index_list.append(new_list)
443
+ index_list = new_index_list
444
+
445
+ # print(" index list is now: {}".format(index_list))
446
+ final_index_list = [last_value + 1]
447
+ final_index_list.extend(index_list[0])
448
+
449
+ ret_val = [i for i in range(len(final_index_list))]
450
+ for i in range(len(final_index_list)):
451
+ ret_val[final_index_list[i]] = orig_list[i]
452
+ return ret_val # [orig_list[i] for i in final_index_list]
453
+
454
+
455
+ def simplify_formula(formula_to_simplify, digits=None):
456
+ if len("{}".format(formula_to_simplify)) > 1500:
457
+ return "{}".format(expand(formula_to_simplify))
458
+ orig_form_str = sympify(formula_to_simplify)
459
+ if len("{}".format(orig_form_str)) > 1000:
460
+ return "{}".format(expand(orig_form_str))
461
+
462
+ if len("{}".format(orig_form_str)) < 700:
463
+ # orig_form_str = simplify(expand(orig_form_str))
464
+ orig_form_str = expand(orig_form_str)
465
+
466
+ rounded = orig_form_str
467
+ for a in sympy.preorder_traversal(orig_form_str):
468
+ if isinstance(a, sympy.Float):
469
+ if digits is not None:
470
+ if np.abs(a) < 10**(-1*digits):
471
+ rounded = rounded.subs(a, 0)
472
+ else:
473
+ rounded = rounded.subs(a, round(a, digits))
474
+ elif np.abs(a) < Settings.big_eps:
475
+ rounded = rounded.subs(a, 0)
476
+
477
+ return "{}".format(rounded)
478
+
479
+
480
+ def eqn_to_str_two_list(eqn_as_list, var_y_index=9999, unary_use_both=False):
481
+ eqn_ops = eqn_as_list[0]
482
+ eqn_vars = eqn_as_list[1]
483
+ current_op = eqn_ops[0]
484
+ # print("eqn_to_str:")
485
+ # print(eqn_ops)
486
+ # print(eqn_vars)
487
+
488
+ if len(eqn_ops) == 1:
489
+
490
+ if type(eqn_vars[0]) is list:
491
+ left_side = "{:.3f}".format(eqn_vars[0][0])
492
+ elif eqn_vars[0] == var_y_index:
493
+ left_side = "y"
494
+ else:
495
+ left_side = "x{}".format(eqn_vars[0])
496
+ if type(eqn_vars[1]) is list:
497
+ right_side = "{:.3f}".format(eqn_vars[1][0])
498
+ elif eqn_vars[1] == var_y_index:
499
+ right_side = "y"
500
+ else:
501
+ right_side = "x{}".format(eqn_vars[1])
502
+
503
+
504
+ else:
505
+ split_point = int((len(eqn_ops) + 1) / 2)
506
+ left_ops = eqn_ops[1:split_point]
507
+ right_ops = eqn_ops[split_point:]
508
+
509
+ left_vars = eqn_vars[:split_point]
510
+ right_vars = eqn_vars[split_point:]
511
+
512
+ left_side = eqn_to_str_two_list([left_ops, left_vars])
513
+ right_side = eqn_to_str_two_list([right_ops, right_vars])
514
+
515
+ left_is_float = False
516
+ right_is_float = False
517
+ left_value = np.nan
518
+ right_value = np.nan
519
+
520
+ if is_float(left_side):
521
+ left_value = float(left_side)
522
+ left_is_float = True
523
+ if is_float(right_side):
524
+ right_value = float(right_side)
525
+ right_is_float = True
526
+
527
+ if current_op == 'id':
528
+ return left_side
529
+
530
+ if current_op == 'sqrt':
531
+ if left_is_float:
532
+ return "{:.3f}".format(np.sqrt(np.abs(left_value)))
533
+ return "sqrt({})".format(left_side)
534
+
535
+ if current_op == 'log':
536
+ if left_is_float:
537
+ return "{:.3f}".format(np.math.log(safe_abs(left_value)))
538
+ return "log({})".format(left_side)
539
+
540
+ if current_op == 'sin':
541
+ if left_is_float:
542
+ return "{:.3f}".format(np.sin(left_value))
543
+ return "sin({})".format(left_side)
544
+
545
+ if current_op == 'exp':
546
+ if left_is_float:
547
+ return "{:.3f}".format(np.exp(left_value))
548
+ return "exp({})".format(left_side)
549
+
550
+ if current_op == 'add':
551
+ if left_is_float and right_is_float:
552
+ return "{:.3f}".format(left_value + right_value)
553
+ return "({} + {})".format(left_side, right_side)
554
+
555
+ if current_op == 'mul':
556
+ if left_is_float and right_is_float:
557
+ return "{:.3f}".format(left_value * right_value)
558
+ return "({} * {})".format(left_side, right_side)
559
+
560
+ if current_op == 'sub':
561
+ if left_is_float and right_is_float:
562
+ return "{:.3f}".format(left_value - right_value)
563
+ return "({} - {})".format(left_side, right_side)
564
+
565
+ if current_op == 'div':
566
+ if left_is_float and right_is_float:
567
+ return "{:.3f}".format(safe_div(left_value, right_value))
568
+ return "({} / {})".format(left_side, right_side)
569
+
570
+ return None
571
+
572
+
573
+ def eqn_to_str(eqn_as_list, var_y_index=9999, unary_use_both=False):
574
+ eqn_ops = eqn_as_list[0]
575
+ eqn_vars = eqn_as_list[1]
576
+ eqn_weights = eqn_as_list[2]
577
+ eqn_biases = eqn_as_list[3]
578
+ current_op = eqn_ops[0]
579
+ # print("eqn_to_str:")
580
+ # print(eqn_ops)
581
+ # print(eqn_vars)
582
+
583
+ if len(eqn_ops) == 1:
584
+
585
+ if eqn_vars[0] == var_y_index:
586
+ left_side = "y"
587
+ else:
588
+ left_side = "({} * x{} + {})".format(eqn_weights[0], eqn_vars[0], eqn_biases[0])
589
+ if eqn_vars[1] == var_y_index:
590
+ right_side = "y"
591
+ else:
592
+ right_side = "({} * x{} + {})".format(eqn_weights[1], eqn_vars[1], eqn_biases[1])
593
+
594
+
595
+ else:
596
+ split_point = int((len(eqn_ops) + 1) / 2)
597
+ left_ops = eqn_ops[1:split_point]
598
+ right_ops = eqn_ops[split_point:]
599
+
600
+ left_vars = eqn_vars[:split_point]
601
+ right_vars = eqn_vars[split_point:]
602
+
603
+ left_weights = eqn_weights[:split_point]
604
+ right_weights = eqn_weights[split_point:]
605
+
606
+ left_biases = eqn_biases[:split_point]
607
+ right_biases = eqn_biases[split_point:]
608
+
609
+ left_side = eqn_to_str([left_ops, left_vars, left_weights, left_biases])
610
+ right_side = eqn_to_str([right_ops, right_vars, right_weights, right_biases])
611
+
612
+ left_is_float = False
613
+ right_is_float = False
614
+ left_value = np.nan
615
+ right_value = np.nan
616
+
617
+ if is_float(left_side):
618
+ left_value = float(left_side)
619
+ left_is_float = True
620
+ if is_float(right_side):
621
+ right_value = float(right_side)
622
+ right_is_float = True
623
+
624
+ if current_op == 'id':
625
+ return left_side
626
+
627
+ if current_op == 'sqrt':
628
+ if left_is_float:
629
+ return "{:.3f}".format(np.sqrt(np.abs(left_value)))
630
+ return "sqrt({})".format(left_side)
631
+
632
+ if current_op == 'log':
633
+ if left_is_float:
634
+ return "{:.3f}".format(np.math.log(safe_abs(left_value)))
635
+ return "log({})".format(left_side)
636
+
637
+ if current_op == 'sin':
638
+ if left_is_float:
639
+ return "{:.3f}".format(np.sin(left_value))
640
+ return "sin({})".format(left_side)
641
+
642
+ if current_op == 'exp':
643
+ if left_is_float:
644
+ return "{:.3f}".format(np.exp(left_value))
645
+ return "exp({})".format(left_side)
646
+
647
+ if current_op == 'add':
648
+ if left_is_float and right_is_float:
649
+ return "{:.3f}".format(left_value + right_value)
650
+ return "({} + {})".format(left_side, right_side)
651
+
652
+ if current_op == 'mul':
653
+ if left_is_float and right_is_float:
654
+ return "{:.3f}".format(left_value * right_value)
655
+ return "({} * {})".format(left_side, right_side)
656
+
657
+ if current_op == 'sub':
658
+ if left_is_float and right_is_float:
659
+ return "{:.3f}".format(left_value - right_value)
660
+ return "({} - {})".format(left_side, right_side)
661
+
662
+ if current_op == 'div':
663
+ if left_is_float and right_is_float:
664
+ return "{:.3f}".format(safe_div(left_value, right_value))
665
+ return "({} / {})".format(left_side, right_side)
666
+
667
+ return None
668
+
669
+ def simple_eqn_to_str(eqn_as_list, var_y_index=9999):
670
+ return simplify_formula(eqn_to_str(eqn_as_list, var_y_index=var_y_index))
671
+
672
+
673
+ def get_samples(n_train, n_batch, train_x, train_y):
674
+ both_samples = np.random.choice(n_train, size=2*n_batch, replace=False)
675
+
676
+ sample = both_samples[:n_batch]
677
+ valid_sample = both_samples[n_batch:]
678
+
679
+ mini_batch_train_data_x = train_x[sample][:][:]
680
+ mini_batch_train_data_y = train_y[sample][:][:]
681
+
682
+ mini_valid_sample_x = train_x[valid_sample][:][:]
683
+ mini_valid_sample_y = train_y[valid_sample][:][:]
684
+ return mini_batch_train_data_x, mini_batch_train_data_y, mini_valid_sample_x, mini_valid_sample_y
685
+
686
+
687
+ ###############################################
688
+ #
689
+ # Plotting functions
690
+ #
691
+ ###############################################
692
+
693
+
694
+ def plot_1d_curve(train_x, train_y_true, train_y_pred, test_x, test_y_true, test_y_pred,
695
+ title="", file_suffix="", show_ground_truth=True):
696
+ plt.figure()
697
+ plt.title(title)
698
+ if show_ground_truth:
699
+ plt.scatter(train_x, train_y_true, color='gray', alpha=0.5, marker='.', label='Ground truth')
700
+ if test_x is not None:
701
+ plt.scatter(test_x, test_y_true, color='gray', alpha=0.5, marker='.')
702
+
703
+ if test_x is not None:
704
+ plt.scatter(test_x, test_y_pred, color='red', alpha=0.7, marker='.', label='Model (test set)')
705
+ plt.scatter(train_x, train_y_pred, color='blue', alpha=0.7, marker='.', label='Model (train set)')
706
+
707
+ for xc in Settings.train_scope:
708
+ plt.axvline(x=xc, color='k', linestyle='dashed', linewidth=2)
709
+
710
+ plt.xlabel("x")
711
+ plt.ylabel("y")
712
+
713
+ plt.legend()
714
+ plt.savefig("images/true_vs_pred_curve{}.png".format(file_suffix))
715
+ plt.close()
716
+
717
+
718
+ def plot_2d_curve(x_1, x_2, y, g,
719
+ title=""):
720
+
721
+ fig = plt.figure(figsize=(11, 5))
722
+ # ax = fig.gca(projection='3d')
723
+ ax = fig.add_subplot(1, 2, 1, projection='3d')
724
+ plt.title("Learned function")
725
+
726
+ surf = ax.plot_surface(x_1, x_2, y, cmap=cm.coolwarm,
727
+ linewidth=0, antialiased=False, label="Ground truth")
728
+
729
+
730
+ plt.xlabel("x")
731
+ plt.ylabel("y")
732
+ fig.colorbar(surf, shrink=0.5, aspect=5)
733
+
734
+ ax = fig.add_subplot(1, 2, 2, projection='3d')
735
+ plt.title("Residual (g)")
736
+
737
+ surf = ax.plot_surface(x_1, x_2, g, cmap=cm.coolwarm,
738
+ linewidth=0, antialiased=False, label="Ground truth")
739
+
740
+ plt.xlabel("x")
741
+ plt.ylabel("y")
742
+ fig.colorbar(surf, shrink=0.5, aspect=5)
743
+
744
+ # plt.show()
745
+
746
+ # plt.legend()
747
+ plt.savefig("images/pred_g_2d.png")
748
+ plt.close()
749
+
750
+
751
+ def plot_predicted_vs_actual(pred_y_train, true_y_train,
752
+ pred_y_test=None, true_y_test=None,
753
+ model_name="Model", set_name="", show=False):
754
+ plt.figure()
755
+ if set_name != "":
756
+ set_name = "({})".format(set_name)
757
+ plt.title('{}: Predicted vs. Actual {}'.format(model_name, set_name))
758
+
759
+ plt.scatter(true_y_train, true_y_train, color='gray', alpha=0.5, marker='.', label='Ground truth')
760
+ if pred_y_test is not None:
761
+ plt.scatter(true_y_test, true_y_test, color='gray', alpha=0.5, marker='.')
762
+
763
+ if pred_y_test is not None:
764
+ plt.scatter(true_y_test, pred_y_test, color="red", alpha=0.6, marker='.', label="{}: Test".format(model_name))
765
+
766
+ plt.scatter(true_y_train, pred_y_train, color="blue", alpha=0.7, marker='.', label="{}: Train".format(model_name))
767
+
768
+ plt.ylabel("Observed")
769
+ plt.xlabel("Expected")
770
+ plt.legend()
771
+
772
+ plt.savefig("images/single_predicted_vs_actual.png")
773
+ if show:
774
+ plt.show()
775
+ plt.close()
776
+
777
+
778
+ # acc_logs: list of accuracy logs to be plotted.
779
+ def plot_accuracy_over_time(iters_log, acc_logs, error_types):
780
+ if len(iters_log) < 2:
781
+ return
782
+ for i in range(len(acc_logs)):
783
+ plt.plot(iters_log[1:], acc_logs[i][1:], label=error_types[i])
784
+ plt.xlabel("Iteration")
785
+ plt.ylabel("Error Scores")
786
+ plt.yscale('log')
787
+ plt.legend()
788
+ plt.savefig("images/accuracy_log.png")
789
+ plt.close()
790
+
791
+
792
+ def plot_hist_of_errors(lists_of_error_scores, all_models, num_trials):
793
+ plt.figure()
794
+ plt.hist([np.log(errors_i) for errors_i in lists_of_error_scores],
795
+ label=[model.short_name for model in all_models])
796
+ plt.legend()
797
+ plt.title("Comparing errors of all methods over {} equations".format(num_trials))
798
+ plt.xlabel("Log of error")
799
+ plt.ylabel("Frequency")
800
+ plt.savefig("images/hist_of_errors.png")
801
+ plt.close()
FeynmanEqns.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # eqn #; # levels; # vars; eqn str; true ops list
2
+ ballot; 1; 2; (x1-x2)/(x1+x2); ["div"]
3
+ sum; 1; 2; x1 + x2; ["id"]
4
+ range; 2; 2; x1**2 * sin(2*x2) / 9.81; ["mul", "sin", "mul"]
5
+ mm
6
+ I.11.19; 1; 6; x1*x2 + x3*x4 + x5*x6; ["mul"]
7
+ mmm
8
+ kin1; 2; 3; x1*x2 + 0.5 * x3 * x2**2; ["mul", "mul", "mul"]
9
+ mm
10
+ mmm
11
+ collision1; 2; 4; (2*x1*x3 - (x1-x2)*x4) / (x1 + x2); ["mul", "id", "div"]
12
+ mmm
13
+ I.12.1; 2; 3; x1 * x2 / (4 * pi * x3**2 / 137); ["mul", "mul", "div"]
14
+ I.10.7a; 3; 2; x1/sqrt(1-x2**2); ["id", "id", "mul", "id", "id", "sqrt", "div"]
15
+ mmm
16
+ I.8.14; 2; 4; sqrt((x2-x1)**2 +(x4-x3)**2); ["mul", "mul", "sqrt"]
17
+ I.6.20a; 2; 2; exp(-x1**2)/sqrt(2*pi); ["mul", "id", "exp"]
18
+ I.29.16; 3; 3; sqrt(x1**2 + x2**2 - 2*x1*x2*cos(x3)); ["mul", "sin", "mul", "id", "mul", "id", "sqrt"]
19
+ AreaTriangle; 2; 3; x1*x2*sin(x3)/2; ["mul", "sin", "mul"]
LearnRules.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+ import numpy as np
4
+
5
+ import LearnTriangles
6
+ import Settings as settings
7
+ from SymbolicFunctionLearner import SFL
8
+
9
+ num_triangles = 1000
10
+ num_fake = 3000
11
+ max_domain = 5
12
+ num_trials = 500
13
+ num_smp_features = 2
14
+ settings.show_output = True
15
+ settings.keep_logs = True
16
+
17
+ settings.mode = "lr"
18
+ # settings.initialize_ops = ["mul", "mul", "mul", "mul", "id", "id", "id"]
19
+ # settings.initialize_ops = ["mul", "mul", "id"]
20
+
21
+
22
+ """" These are the things to change"""
23
+ var_names = LearnTriangles.get_xy_var_names()
24
+
25
+ # real_data = LearnTriangles.get_right_triangle_data(num_triangles, max_domain)
26
+ # real_data = LearnTriangles.get_angle_data(num_triangles)
27
+ real_data = LearnTriangles.get_xy_data(num_triangles, max_domain)
28
+ real_y = [1 for v in real_data]
29
+
30
+ fake_data = LearnTriangles.get_fake_xy_data(num_triangles, max_domain)
31
+ # fake_data = LearnTriangles.get_fake_angles(num_triangles)
32
+ # fake_data = LearnTriangles.get_triangle_data(num_triangles, max_domain)
33
+ fake_y = [0 for _ in fake_data]
34
+
35
+ # real_test_data = LearnTriangles.get_right_triangle_data(num_triangles, max_domain * 2)
36
+ # real_test_data = LearnTriangles.get_angle_data(num_triangles)
37
+ real_test_data = LearnTriangles.get_xy_data(num_triangles, max_domain)
38
+ real_test_y = [1 for v in real_test_data]
39
+
40
+ # fake_test_data = LearnTriangles.get_triangle_data(num_triangles, max_domain * 2)
41
+ # fake_test_data = LearnTriangles.get_fake_angles(num_triangles)
42
+ fake_test_data = LearnTriangles.get_fake_xy_data(num_triangles, max_domain)
43
+ fake_test_y = [0 for _ in fake_test_data]
44
+
45
+ """ Don't change after this """
46
+
47
+ print("real data: ")
48
+ for r_d in real_data[:5]:
49
+ print(r_d)
50
+ print("real y:")
51
+ for r_d in real_y[:5]:
52
+ print(r_d)
53
+ print("fake data:")
54
+ for r_d in fake_data[:5]:
55
+ print(r_d)
56
+ print("fake y:")
57
+ for r_d in fake_y[:5]:
58
+ print(r_d)
59
+
60
+ full_data = real_data.copy()
61
+ full_data.extend(fake_data)
62
+ full_labels = real_y.copy()
63
+ full_labels.extend(fake_y)
64
+
65
+ full_test_data = real_test_data.copy()
66
+ full_test_data.extend(fake_test_data)
67
+ full_test_labels = real_test_y.copy()
68
+ full_test_labels.extend(fake_test_y)
69
+
70
+ # print("full data:\n{}".format(full_data))
71
+ # print("full y:\n{}".format(full_labels))
72
+ #
73
+ # for datum in real_data:
74
+ # print(datum[0]*datum[4] - datum[1]*datum[3])
75
+
76
+
77
+ our_results = []
78
+
79
+ settings.true_eqn = "0*x1"
80
+ settings.num_features = num_smp_features
81
+
82
+ model = SFL()
83
+
84
+ for trial_round in range(num_trials):
85
+ sampled_features = np.random.choice(range(len(real_data[0])), num_smp_features, replace=True)
86
+
87
+ sampled_features = [0, 1]
88
+
89
+ data = [[row[smp_i] for smp_i in sampled_features] for row in full_data]
90
+ test_data = [[row[smp_i] for smp_i in sampled_features] for row in full_test_data]
91
+
92
+ smp_var_names = [var_names[smp_i] for smp_i in sampled_features]
93
+ print("Trial round {} of {}.".format(trial_round + 1, num_trials))
94
+ print(" Using variables {}.".format(smp_var_names))
95
+
96
+ settings.fixed_x = []
97
+ settings.fixed_y = []
98
+ for line in data:
99
+ settings.fixed_x.append(line)
100
+ settings.fixed_y = full_labels
101
+
102
+ # print("fixed_x: {}, {}".format(len(settings.fixed_x), len(settings.fixed_x[0])))
103
+ # print("fixed_y: {}".format(len(settings.fixed_y)))
104
+
105
+ model.reset(var_names=smp_var_names)
106
+
107
+ # train_X = DataUtils.generate_data(settings.train_N, n_vars=model.n_input_variables,
108
+ # avoid_zero=settings.avoid_zero)
109
+ # valid_X = DataUtils.generate_data(settings.train_N, n_vars=model.n_input_variables,
110
+ # avoid_zero=settings.avoid_zero)
111
+ # test_X = DataUtils.generate_data(settings.test_N, n_vars=model.n_input_variables,
112
+ # min_x=settings.test_scope[0],
113
+ # max_x=settings.test_scope[1])
114
+ train_X = np.array(data)
115
+ train_Y = full_labels
116
+
117
+ test_X = np.array(test_data)
118
+ test_Y = full_test_labels
119
+
120
+ train_X = train_X.reshape([-1, settings.num_dims_per_feature, settings.num_features])
121
+ test_X = test_X.reshape([-1, settings.num_dims_per_feature, settings.num_features])
122
+
123
+ start_time = time.time()
124
+ best_model, best_iter, best_err = model.repeat_train(train_X, train_Y,
125
+ settings.num_train_repeat_processes,
126
+ test_x=test_X, test_y=test_Y)
127
+ running_time = time.time() - start_time
128
+
129
+ print("best_model: {}".format(best_model))
130
+ print("----------------------")
131
+ print("Finished this experiment. Took {:.2f} minutes.\n".format(running_time / 60))
132
+
133
+ our_results.append([best_err, best_model, smp_var_names])
134
+ our_results = sorted(our_results, key=lambda entry: entry[0])
135
+
136
+ output_file = open("images/triangle_output.txt", "w")
137
+ for entry in our_results:
138
+ output_file.write("{}\n{}\n{}\n\n".format(entry[0], entry[2], entry[1]))
139
+ output_file.close()
140
+
141
+ print("Final solution found at attempt {}:".format(best_iter))
142
+ print("y = {}".format(best_model))
143
+ print("Test error: {}".format(best_err))
144
+ if best_err < 0.02:
145
+ print("Attained error less than 0.02 - great!")
146
+ print()
LearnTriangles.py ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def get_simple_data(num_points, max_domain):
5
+ full_data = []
6
+ for i in range(num_points):
7
+ new_datum = [np.random.uniform(0, max_domain),
8
+ np.random.uniform(0, max_domain),
9
+ np.random.uniform(0, max_domain)]
10
+ full_data.append(new_datum)
11
+ return full_data
12
+
13
+
14
+ def get_simple_var_names():
15
+ return ["a", "b", "c"]
16
+
17
+
18
+ def get_xy_var_names():
19
+ return ["x", "y"]
20
+
21
+
22
+ def get_angle_data(num_data):
23
+ full_data = []
24
+ for i in range(num_data):
25
+ theta = np.random.uniform(0, 2 * np.pi)
26
+ while np.abs(theta - np.pi / 2) < 1e-3 or np.abs(theta - 3 * np.pi / 2) < 1e-3:
27
+ theta = np.random.uniform(0, 2 * np.pi)
28
+ new_datum = [np.sin(theta), np.cos(theta), np.tan(theta)]
29
+ full_data.append(new_datum)
30
+ return full_data
31
+
32
+
33
+ def get_fake_angles(num_data):
34
+ full_data = []
35
+ for i in range(num_data):
36
+ [s, c] = np.random.uniform(-1, 1, 2)
37
+ t = np.random.uniform(-5, 5)
38
+ new_datum = [s, c, t]
39
+ full_data.append(new_datum)
40
+ return full_data
41
+
42
+
43
+ def get_xy_data(num_data, max_domain):
44
+ full_data = []
45
+ for i in range(num_data):
46
+ # t = np.random.uniform(0, 2 * np.pi)
47
+ # r = 2 + 3 * np.cos(t)
48
+ # # r = 5 * np.cos(2*t)/np.cos(t)
49
+ #
50
+ # x = r * np.cos(t)
51
+ # y = r * np.sin(t)
52
+
53
+ y = np.random.uniform(-3, 2)
54
+ sign = np.random.choice([-1, 1])
55
+ x = sign * np.sqrt(np.abs(2 * np.sin(y) + 5 - y ** 3))
56
+ full_data.append([x, y])
57
+ return full_data
58
+
59
+
60
+ def get_fake_xy_data(num_data, max_domain):
61
+ full_data = []
62
+ for i in range(num_data):
63
+ [x, y] = np.random.uniform(0, max_domain, 2)
64
+ full_data.append([x, y])
65
+ return full_data
66
+
67
+
68
+
69
+ def get_triangle_data(num_triangles, max_domain):
70
+ full_data = []
71
+ for i in range(num_triangles):
72
+ [x1, y1, x2, y2, x3, y3] = np.random.uniform(0, max_domain, 6)
73
+
74
+ a = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
75
+ b = np.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2)
76
+ c = np.sqrt((x1 - x3) ** 2 + (y1 - y3) ** 2)
77
+
78
+ va = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))
79
+ vb = np.arccos((c ** 2 + a ** 2 - b ** 2) / (2 * a * c))
80
+ vc = np.arccos((a ** 2 + b ** 2 - c ** 2) / (2 * b * a))
81
+
82
+ sa, sb, sc = np.sin([va, vb, vc])
83
+ ca, cb, cc = np.cos([va, vb, vc])
84
+ ta, tb, tc = np.tan([va, vb, vc])
85
+
86
+ new_datum = []
87
+ # new_datum.extend([x1, x2, x3])
88
+ # new_datum.extend([y1, y2, y3])
89
+ new_datum.extend([a, b, c])
90
+ # new_datum.extend([va, vb, vc])
91
+ # new_datum.extend([sa, sb, sc])
92
+ # new_datum.extend([ca, cb, cc])
93
+ # new_datum.extend([ta, tb, tc])
94
+
95
+ full_data.append(new_datum)
96
+ return full_data
97
+
98
+
99
+ def get_right_triangle_data(num_triangles, max_domain):
100
+ full_data = []
101
+ for i in range(num_triangles):
102
+ [s1, s2] = np.random.uniform(0, max_domain, 2)
103
+ c = max(s1, s2)
104
+ a = min(s1, s2)
105
+ b = np.sqrt(c * c - a * a)
106
+
107
+ va = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))
108
+ vb = np.arccos((c ** 2 + a ** 2 - b ** 2) / (2 * a * c))
109
+ vc = np.arccos((a ** 2 + b ** 2 - c ** 2) / (2 * b * a))
110
+
111
+ sa, sb, sc = np.sin([va, vb, vc])
112
+ ca, cb, cc = np.cos([va, vb, vc])
113
+ ta, tb, tc = np.tan([va, vb, vc])
114
+
115
+ new_datum = []
116
+ new_datum.extend([a, b, c])
117
+ # new_datum.extend([sa, sb, sc])
118
+ # new_datum.extend([ca, cb, cc])
119
+ # new_datum.extend([ta, tb, tc])
120
+
121
+ full_data.append(new_datum)
122
+
123
+ return full_data
124
+
125
+
126
+ def get_fake_triangle_data(num_triangles, max_domain):
127
+ full_data = []
128
+ for i in range(num_triangles):
129
+ [a, b, c] = np.random.uniform(0, max_domain, 3)
130
+ [sa, sb, sc] = np.random.uniform(-1, 1, 3)
131
+ [ca, cb, cc] = np.random.uniform(-1, 1, 3)
132
+ [ta, tb, tc] = np.random.uniform(-5, 5, 3)
133
+
134
+ new_datum = []
135
+ new_datum.extend([a, b, c])
136
+ # new_datum.extend([va, vb, vc])
137
+ new_datum.extend([sa, sb, sc])
138
+ new_datum.extend([ca, cb, cc])
139
+ new_datum.extend([ta, tb, tc])
140
+
141
+ # new_datum.extend([va, vb, vc])
142
+ # new_datum.extend([a, 2*a])
143
+ # new_datum.extend([ta, tb, tc])
144
+
145
+ full_data.append(new_datum)
146
+ return full_data
147
+
148
+
149
+ def get_non_triangle_data(num_triangles, max_domain):
150
+ full_data = []
151
+ for i in range(num_triangles):
152
+ [x1, y1, x2, y2, x3, y3, x4, y4] = np.random.uniform(0, max_domain, 8)
153
+
154
+ a = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
155
+ b = np.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2)
156
+ c = np.sqrt((x4 - x3) ** 2 + (y4 - y3) ** 2)
157
+ d = np.sqrt((x1 - x4) ** 2 + (y1 - y4) ** 2)
158
+ e24 = np.sqrt((x4 - x2) ** 2 + (y4 - y2) ** 2)
159
+ e13 = np.sqrt((x3 - x1) ** 2 + (y3 - y1) ** 2)
160
+
161
+ va = np.arccos((b ** 2 + c ** 2 - e24 ** 2) / (2 * b * c))
162
+ vb = np.arccos((d ** 2 + c ** 2 - e13 ** 2) / (2 * d * c))
163
+ vc = np.arccos((d ** 2 + a ** 2 - e24 ** 2) / (2 * d * a))
164
+
165
+ sa, sb, sc = np.sin([va, vb, vc])
166
+ ca, cb, cc = np.cos([va, vb, vc])
167
+ ta, tb, tc = np.tan([va, vb, vc])
168
+
169
+ new_datum = []
170
+ new_datum.extend([a, b, c])
171
+ # new_datum.extend([va, vb, vc])
172
+ new_datum.extend([sa, sb, sc])
173
+ new_datum.extend([ca, cb, cc])
174
+ # new_datum.extend([ta, tb, tc])
175
+ full_data.append(new_datum)
176
+ return full_data
177
+
178
+ def get_var_names():
179
+ # var_names = ["a", "b", "c"]
180
+ var_names = []
181
+ var_names.extend(["sin(x)", "cos(x)", "tan(x)"])
182
+ # var_names.extend(["A", "B", "C"])
183
+ var_names.extend(["sin(A)", "sin(B)", "sin(C)"])
184
+ var_names.extend(["cos(A)", "cos(B)", "cos(C)"])
185
+ var_names.extend(["tan(A)", "tan(B)", "tan(C)"])
186
+ return var_names
187
+ #
188
+ # our_results = []
189
+ #
190
+ # settings.true_eqn = "0*x1"
191
+ # settings.num_features = num_smp_features
192
+ # settings.show_output = False
193
+ # settings.keep_logs = False
194
+ #
195
+ # model = SFL()
196
+ #
197
+ # for trial_round in range(num_trials):
198
+ # sampled_features = np.random.choice(range(len(full_data[0])), num_smp_features, replace=True)
199
+ #
200
+ # # sampled_features = [3,6]
201
+ # data = [[row[smp_i] for smp_i in sampled_features] for row in full_data]
202
+ # smp_var_names = [var_names[smp_i] for smp_i in sampled_features]
203
+ # print("Trial round {} of {}.".format(trial_round + 1, num_trials))
204
+ # print(" Using variables {}.".format(smp_var_names))
205
+ #
206
+ # settings.fixed_x = []
207
+ # settings.fixed_y = []
208
+ # for line in data:
209
+ # settings.fixed_x.append(line)
210
+ # settings.fixed_y.append(0)
211
+ #
212
+ # model.reset(var_names=smp_var_names)
213
+ #
214
+ # # train_X = DataUtils.generate_data(settings.train_N, n_vars=model.n_input_variables,
215
+ # # avoid_zero=settings.avoid_zero)
216
+ # # valid_X = DataUtils.generate_data(settings.train_N, n_vars=model.n_input_variables,
217
+ # # avoid_zero=settings.avoid_zero)
218
+ # # test_X = DataUtils.generate_data(settings.test_N, n_vars=model.n_input_variables,
219
+ # # min_x=settings.test_scope[0],
220
+ # # max_x=settings.test_scope[1])
221
+ # train_X = np.array(data)
222
+ # valid_X = np.array(data)
223
+ # test_X = np.array(data)
224
+ #
225
+ # train_X = train_X.reshape([-1, settings.num_dims_per_feature, settings.num_features])
226
+ # valid_X = valid_X.reshape([-1, settings.num_dims_per_feature, settings.num_features])
227
+ # test_X = test_X.reshape([-1, settings.num_dims_per_feature, settings.num_features])
228
+ #
229
+ # start_time = time.time()
230
+ # best_model, best_iter, best_err = model.repeat_train(train_X,
231
+ # settings.num_train_repeat_processes,
232
+ # test_x=test_X)
233
+ # running_time = time.time() - start_time
234
+ #
235
+ # print("best_model: {}".format(best_model))
236
+ # print("----------------------")
237
+ # print("Finished this experiment. Took {:.2f} minutes.\n".format(running_time / 60))
238
+ #
239
+ # our_results.append([best_err, best_model, smp_var_names])
240
+ # our_results = sorted(our_results, key=lambda entry: entry[0])
241
+ #
242
+ # output_file = open("images/triangle_output.txt", "w")
243
+ # for entry in our_results:
244
+ # output_file.write("{}\n{}\n{}\n\n".format(entry[0], entry[2], entry[1]))
245
+ # output_file.close()
246
+ #
247
+ # print("Final solution found at attempt {}:".format(best_iter))
248
+ # print("y = {}".format(best_model))
249
+ # print("Test error: {}".format(best_err))
250
+ # if best_err < 0.02:
251
+ # print("Attained error less than 0.02 - great!")
252
+ # print()
MLP_Model.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+ import numpy as np
4
+ from sklearn.neural_network import MLPRegressor
5
+ from sklearn.utils.validation import column_or_1d
6
+
7
+ import Settings as settings
8
+ from DataUtils import make_y_multi_safe
9
+
10
+ hidden_layer_sizes = (5, 5)
11
+ max_iter_mlp = 500000
12
+
13
+
14
+ class MLP_Model:
15
+ def __init__(self):
16
+ self.name = "MLP Model"
17
+ self.short_name = "MLP"
18
+ self.hidden_layer_sizes = hidden_layer_sizes
19
+ self.solver = 'adam'
20
+ self.max_iter = max_iter_mlp
21
+ self.warm_start = False
22
+ self.verbose = False
23
+ self.est_mlp = MLPRegressor(hidden_layer_sizes=self.hidden_layer_sizes,
24
+ solver=self.solver,
25
+ activation='relu',
26
+ max_iter=self.max_iter,
27
+ verbose=self.verbose,
28
+ tol=1e-7,
29
+ warm_start=self.warm_start,
30
+ n_iter_no_change=100)
31
+
32
+ def get_formula_string(self):
33
+ return "(neural black box)"
34
+ # current_inputs = ["X{}".format(i + 1) for i in range(settings.num_features)]
35
+ # # print(current_inputs)
36
+ # matrices = self.est_mlp.coefs_
37
+ # vectors = self.est_mlp.intercepts_
38
+ # for i in range(len(matrices)):
39
+ # current_outputs = []
40
+ #
41
+ # for j in range(matrices[i].shape[1]):
42
+ # current_term = [vectors[i][j]]
43
+ # for k in range(matrices[i].shape[0]):
44
+ # sys.stdout.flush()
45
+ # current_term.append(["*", matrices[i][k][j], current_inputs[k]])
46
+ #
47
+ # current_output = current_term[-1]
48
+ # for k in range(len(current_term), 1, -1):
49
+ # current_output = ["+", current_term[k - 2], current_output]
50
+ # current_outputs.append(current_output)
51
+ # current_inputs = [["max", 0, old_out] for old_out in current_outputs]
52
+ #
53
+ # # [-1] since we don't do relu activation on the last layer.
54
+ # return current_inputs[0][-1]
55
+
56
+ def get_formula(self):
57
+ return "(neural black box)"
58
+ # return self.get_formula_string()
59
+
60
+ def train(self, X, Y):
61
+ X = np.reshape(X, [X.shape[0], -1])
62
+ Y = np.reshape(Y, [-1, 1])
63
+ Y = column_or_1d(Y)
64
+ self.est_mlp.fit(X, Y)
65
+ return None
66
+
67
+ def predict(self, X):
68
+ return self.est_mlp.predict(X)
69
+
70
+ # Mean square error
71
+ def test(self, X, Y):
72
+ X = np.reshape(X, [X.shape[0], -1])
73
+ y_hat = np.reshape(self.est_mlp.predict(X), [1, -1])[0]
74
+ y_gold = np.reshape(Y, [1, -1])[0]
75
+ our_sum = 0
76
+ for i in range(len(y_gold)):
77
+ our_sum += (y_hat[i] - y_gold[i]) ** 2
78
+
79
+ return our_sum / len(y_gold)
80
+
81
+ def reset(self):
82
+ self.est_mlp = MLPRegressor(hidden_layer_sizes=self.hidden_layer_sizes,
83
+ solver=self.solver,
84
+ activation='relu',
85
+ max_iter=self.max_iter,
86
+ verbose=self.verbose,
87
+ tol=1e-7,
88
+ warm_start=self.warm_start,
89
+ n_iter_no_change=100)
90
+
91
+ def soft_reset(self):
92
+ self.est_mlp = MLPRegressor(hidden_layer_sizes=self.hidden_layer_sizes,
93
+ solver=self.solver,
94
+ activation='relu',
95
+ max_iter=self.max_iter,
96
+ verbose=self.verbose,
97
+ tol=1e-7,
98
+ warm_start=self.warm_start,
99
+ n_iter_no_change=100)
100
+
101
+ def get_simple_formula(self, digits=None):
102
+ full_formula = self.get_formula_string()
103
+ return full_formula
104
+ # return DataUtils.simplify_formula(full_formula, digits=digits)
105
+
106
+ def real_repeat_train(self, x, y=None,
107
+ num_repeats=settings.num_train_repeat_processes,
108
+ test_x=None, test_y=None,
109
+ verbose=True):
110
+
111
+ # we still reduce train set size if only 1 repeat
112
+ train_set_size = int(len(x) * settings.quick_train_fraction + 0.1)
113
+
114
+ x = np.array(x)
115
+ if y is not None:
116
+ y = np.array(y)
117
+
118
+ sample = np.random.choice(range(x.shape[0]), size=train_set_size, replace=False)
119
+ train_x = x[sample][:]
120
+ if y is not None:
121
+ train_y = y[sample]
122
+ else:
123
+ train_y = None
124
+
125
+ out_sample = [aaa for aaa in range(x.shape[0]) if aaa not in sample]
126
+ valid_x = x[out_sample][:]
127
+ if y is not None:
128
+ valid_y = y[out_sample]
129
+ # valid_y = self.make_y_multi_safe(valid_y)
130
+ else:
131
+ valid_y = None
132
+
133
+ best_formula = ""
134
+ best_iter = 0
135
+ best_validation = 999999
136
+ best_err = 999999
137
+ old_time = time.time()
138
+
139
+ if verbose:
140
+ print("Beginning {} repeat sessions of {} iterations each.".format(num_repeats,
141
+ settings.num_train_steps_in_repeat_mode))
142
+ print()
143
+ start_time = time.time()
144
+ old_time = start_time
145
+
146
+ for train_iter in range(1, 1 + num_repeats):
147
+ if verbose:
148
+ print("Repeated train session {} of {}.".format(train_iter, num_repeats))
149
+
150
+ self.soft_reset()
151
+ self.train(train_x, train_y)
152
+
153
+ valid_err = self.test(valid_x, valid_y)
154
+
155
+ current_time = time.time()
156
+ if verbose:
157
+ # print(self.get_simple_formula())
158
+ print("Attained validation error: {:.5f}".format(valid_err))
159
+
160
+ if valid_err < best_validation:
161
+ best_validation = valid_err
162
+ best_formula = self.get_simple_formula()
163
+ best_iter = train_iter
164
+ if test_x is not None:
165
+ safe_test_y = make_y_multi_safe(test_y)
166
+ best_err = self.test(test_x, safe_test_y)
167
+ else:
168
+ best_err = valid_err
169
+ if verbose:
170
+ print(">>> New best model!")
171
+ print(best_formula)
172
+
173
+ if verbose:
174
+ iters_per_minute = 60.0 / (current_time - old_time)
175
+ print("Took {:.2f} minutes.".format((current_time - old_time) / 60))
176
+ print("Est. {:.2f} minutes remaining.".format((num_repeats - train_iter) / iters_per_minute))
177
+ print()
178
+ old_time = current_time
179
+
180
+ if verbose:
181
+ print("Total time for repeat process: {:.2f} minutes.".format((time.time() - start_time) / 60))
182
+
183
+ return best_formula, best_iter, best_err
184
+
185
+ # Does not repeat train. sorry.
186
+ def repeat_train(self, x, y=None,
187
+ num_repeats=settings.num_train_repeat_processes,
188
+ test_x=None, test_y=None,
189
+ verbose=True):
190
+
191
+ # we still reduce train set size if only 1 repeat
192
+ train_set_size = int(len(x) * settings.quick_train_fraction + 0.1)
193
+
194
+ x = np.array(x)
195
+ if y is not None:
196
+ y = np.array(y)
197
+
198
+ sample = np.random.choice(range(x.shape[0]), size=train_set_size, replace=False)
199
+ train_x = x[sample][:]
200
+ if y is not None:
201
+ train_y = y[sample]
202
+ else:
203
+ train_y = None
204
+
205
+ out_sample = [aaa for aaa in range(x.shape[0]) if aaa not in sample]
206
+ valid_x = x[out_sample][:]
207
+ if y is not None:
208
+ valid_y = y[out_sample]
209
+ # valid_y = self.make_y_multi_safe(valid_y)
210
+ else:
211
+ valid_y = None
212
+
213
+ if verbose:
214
+ start_time = time.time()
215
+ old_time = start_time
216
+
217
+ self.soft_reset()
218
+ self.train(train_x, train_y)
219
+
220
+ current_time = time.time()
221
+
222
+ best_formula = self.get_simple_formula()
223
+ if test_x is not None:
224
+ safe_test_y = make_y_multi_safe(test_y)
225
+ best_err = self.test(test_x, safe_test_y)
226
+ else:
227
+ best_err = self.test(valid_x, valid_y)
228
+ if verbose:
229
+ print(">>> New best model!")
230
+ print(best_formula)
231
+
232
+ if verbose:
233
+ print("Took {:.2f} minutes.".format((current_time - old_time) / 60))
234
+ print()
235
+
236
+ if verbose:
237
+ print("Total time for repeat process: {:.2f} minutes.".format((time.time() - start_time) / 60))
238
+
239
+ return best_formula, 0, best_err
RegressorTest.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """""""""""""""""""""""""""""""""
2
+ This file is for running.
3
+ Do not modify this file.
4
+
5
+ For running: DiffEqnSolver.py
6
+ For modifying: settings.py
7
+ """""""""""""""""""""""""""""""""
8
+
9
+ import os
10
+ import time
11
+
12
+ import numpy as np
13
+ from pysr import pysr, best
14
+
15
+ import DataUtils
16
+ import Settings as settings
17
+ from SymbolicFunctionLearner import SFL
18
+
19
+ # Dataset
20
+ X = 2 * np.random.randn(100, 5)
21
+ y = 2 * np.cos(X[:, 3]) + X[:, 0] ** 2 - 2
22
+
23
+ # Learn equations
24
+ equations = pysr(X, y, niterations=5,
25
+ binary_operators=["plus", "mult"],
26
+ unary_operators=[
27
+ "cos", "exp", "sin"])
28
+ # Pre-defined library of operators (see https://pysr.readthedocs.io/en/latest/docs/operators/)
29
+ # "inv(x) = 1/x"]) # Define your own operator! (Julia syntax)
30
+
31
+ ... # (you can use ctl-c to exit early)
32
+
33
+ print(best(equations))
34
+
35
+
36
+
37
+ settings.mode = "sr"
38
+
39
+ if not os.path.exists('images'):
40
+ os.makedirs('images')
41
+
42
+ input_file = open("FeynmanEqns.txt", "r")
43
+ input_lines = input_file.readlines()
44
+ input_file.close()
45
+ for line in input_lines[1:]:
46
+ line_parts = line.strip().split(";")
47
+ eqn_name = line_parts[0].strip()
48
+ settings.n_tree_layers = int(line_parts[1].strip())
49
+ settings.num_features = int(line_parts[2].strip())
50
+ eqn_str = line_parts[3].strip()
51
+ print("True equation: {}".format(eqn_str))
52
+ settings.true_eqn = eqn_str
53
+ settings.initialize_ops = eval(line_parts[4].strip())
54
+ print(settings.initialize_ops)
55
+
56
+ # Set up data
57
+ fixed_x = DataUtils.generate_data(settings.train_N, n_vars=settings.num_features)
58
+ print(fixed_x.shape)
59
+ fixed_y = DataUtils.true_function(fixed_x)
60
+ print(len(fixed_y))
61
+
62
+ settings.fixed_x = []
63
+ settings.fixed_y = []
64
+ for i in range(settings.train_N):
65
+ settings.fixed_x.append(fixed_x[i, :].tolist()[0])
66
+ settings.fixed_y.append(fixed_y[i])
67
+
68
+ current_model = SFL()
69
+
70
+ print('\nBeginning experiment: {}'.format(current_model.name))
71
+
72
+ print("{} tree layers.".format(settings.n_tree_layers))
73
+ print("{} features of {} component(s) each.".format(settings.num_features, settings.num_dims_per_feature))
74
+ print("{} components in output.".format(settings.n_dims_in_output))
75
+ print("{} operators: {}.".format(len(current_model.function_set),
76
+ current_model.function_set))
77
+
78
+ train_errors = []
79
+ valid_errors = []
80
+ test_errors = []
81
+ true_eqns = []
82
+
83
+ # train_X = DataUtils.generate_data(settings.train_N, n_vars=current_model.n_input_variables,
84
+ # avoid_zero=settings.avoid_zero)
85
+ # valid_X = DataUtils.generate_data(settings.train_N, n_vars=current_model.n_input_variables,
86
+ # avoid_zero=settings.avoid_zero)
87
+ # test_X = DataUtils.generate_data(settings.test_N, n_vars=current_model.n_input_variables,
88
+ # min_x=settings.test_scope[0],
89
+ # max_x=settings.test_scope[1])
90
+ train_X = fixed_x
91
+ test_X = fixed_x
92
+ train_Y = fixed_y
93
+ test_Y = fixed_y
94
+
95
+ print("\n========================")
96
+ print("Starting Solver.")
97
+ print("==========================\n")
98
+
99
+ # Train the model from scratch several times, keeping the best one.
100
+ start_time = time.time()
101
+ best_model, best_iter, best_err = current_model.repeat_train(train_X, train_Y,
102
+ settings.num_train_repeat_processes,
103
+ test_x=test_X, test_y=test_Y)
104
+ running_time = time.time() - start_time
105
+
106
+ print("best_model: {}".format(best_model))
107
+ print("----------------------")
108
+ print("Finished regression. Took {:.2f} minutes.\n".format(running_time / 60))
109
+
110
+ print("Final solution found at attempt {}:".format(best_iter))
111
+ print("y = {}".format(best_model))
112
+ print("Test error: {}".format(best_err))
113
+ if best_err < 0.02:
114
+ print("Attained error less than 0.02 - great!")
115
+ print()
Settings.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """""""""""""""""""""""""""""""""
2
+ This file is for modifying.
3
+ Do not run this file.
4
+
5
+ For running: RegressorTest.py
6
+ For modifying: Settings.py
7
+ """""""""""""""""""""""""""""""""
8
+ import numpy as np
9
+ import tensorflow as tf
10
+
11
+ """""""""""""""""""""""""""
12
+ Settings that can change
13
+ """""""""""""""""""""""""""
14
+ # Determines complexity of tree
15
+ n_tree_layers = 3
16
+
17
+ # Allowable operators for tree nodes
18
+ # function_set = ['id', 'mul', 'sqrt', 'sin', 'div', 'log']
19
+ function_set = ["id", "mul", "sin", "sqrt"]
20
+
21
+ num_features = 1
22
+ num_dims_per_feature = 1
23
+ n_dims_in_output = 1
24
+
25
+ train_scope = [0, 5]
26
+ test_scope = [y * 2 for y in train_scope]
27
+
28
+ num_train_repeat_processes = 5
29
+ num_train_steps_in_repeat_mode = 8000
30
+
31
+ """""""""""""""""""""""""""
32
+ Display and log settings
33
+ """""""""""""""""""""""""""
34
+
35
+ show_output = False
36
+ keep_logs = False
37
+ output_freq = 49000
38
+ plot_frequency = 500000
39
+ save_all_formulas = False
40
+
41
+ max_formula_output_length = 400
42
+
43
+ """""""""""""""""""""""""""
44
+ Tree settings
45
+ """""""""""""""""""""""""""
46
+ use_both_for_unary = True
47
+ non_const = False
48
+ use_leaf_sm = False
49
+
50
+
51
+ """""""""""""""""""""""""""
52
+ Domain parameters
53
+ """""""""""""""""""""""""""
54
+
55
+ fpe_example = 0
56
+
57
+ max_x = np.pi
58
+
59
+ train_scope2 = [0, 5]
60
+ test_scope2 = test_scope.copy() # [0, 5]
61
+
62
+ avoid_zero = False
63
+ # if fpe_example == 4:
64
+ # avoid_zero = True
65
+
66
+
67
+ """""""""""""""""""""""""""
68
+ Define the ODE here
69
+ """""""""""""""""""""""""""
70
+ # options: mode = "sr", "de", "lr"
71
+ mode = "de"
72
+
73
+ # This is the "g" function that defines the ODE problem.
74
+ def implicit_function(full_x, y, y_p, y_pp):
75
+ # Implicit function is 0 if we are doing symbolic regression
76
+ if mode == "sr":
77
+ return y * 0.0
78
+
79
+ y_p1 = y_p[0]
80
+ y_p2 = y_p[1]
81
+ y_p3 = y_p[2]
82
+
83
+ y_pp1 = y_pp[0]
84
+ y_pp2 = y_pp[1]
85
+ y_pp12 = y_pp[2]
86
+
87
+ x = tf.reshape(full_x[:, 0, 0], [-1, 1, 1])
88
+ t = tf.reshape(full_x[:, 0, -1], [-1, 1, 1])
89
+ if num_features > 1:
90
+ w = tf.reshape(full_x[:, 0, 1], [-1, 1, 1])
91
+
92
+ ret_val = None
93
+
94
+ """ Lane-Emden Equation """
95
+ # emden_m = 0
96
+ # ret_val = y_pp1 + 2.0 * tf.math.divide_no_nan(y_p1, x)
97
+ # ret_val += y ** emden_m
98
+
99
+ """ Bell curve integral """
100
+ # ret_val = tf.math.exp(-1.0 * tf.square(x)) - y_p1
101
+
102
+ """ One dimensional wave equation """
103
+ # c = 1.0
104
+ # ret_val = y_pp2 - c**2 * y_pp1
105
+
106
+ """ One dimensional heat equation """
107
+ # c = 1.0
108
+ # ret_val = y_p2 - c**2 * y_pp1 - tf.math.cos(x)
109
+
110
+ """ Inhomogeneous wave equation """
111
+ # ret_val = y_pp1 - y_pp2 - 2
112
+
113
+ """ Two dimensional Laplace equation """
114
+ # ret_val = y_pp2 + y_pp1
115
+
116
+ ret_val = y_p1 - 2 * x
117
+
118
+
119
+
120
+ """ FP Eqn """
121
+ if fpe_example == 1:
122
+ # Example 1
123
+ a = -1.0
124
+ a_p = 0.0
125
+ b = 1.0
126
+ b_p = 0.0
127
+ b_pp = 0.0
128
+ elif fpe_example == 2:
129
+ # Example 2
130
+ a = x
131
+ a_p = 1.0
132
+ b = tf.math.square(x) / 2
133
+ b_p = x
134
+ b_pp = 1.0
135
+ elif fpe_example == 3:
136
+ # Example 3
137
+ a = -1.0 - x
138
+ a_p = -1.0
139
+ b = tf.multiply(x ** 2, tf.math.exp(t))
140
+ b_p = 2 * x * tf.math.exp(t)
141
+ b_pp = 2 * tf.math.exp(t)
142
+ elif fpe_example == 4:
143
+ # Example 4
144
+ a = 4.0 * tf.math.divide_no_nan(y, x) - x / 3.0
145
+ a_p = 4.0 * (tf.math.divide_no_nan(y_p1, x) - tf.math.divide_no_nan(y, x ** 2)) - 1.0 / 3
146
+ b = y
147
+ b_p = y_p1
148
+ b_pp = y_pp1
149
+ elif fpe_example == 6:
150
+ # Example 5
151
+ a = 0.0
152
+ a_p = 0.0
153
+ b = 0.5
154
+ b_p = 0.0
155
+ b_pp = 0.0
156
+
157
+ if fpe_example > 0:
158
+ t1 = tf.multiply(y, b_pp - a_p)
159
+ t2 = tf.multiply(y_p1, 2 * b_p - a)
160
+ t3 = tf.multiply(y_pp1, b)
161
+ # print("a: {}".format(a.shape))
162
+ # print("a_p: {}".format(a_p.shape))
163
+ # print("b: {}".format(a.shape))
164
+ # print("b_p: {}".format(b_p.shape))
165
+ # print("b_pp: {}".format(b_pp.shape))
166
+ # print("t1: {}".format(t1.shape))
167
+ # print("t2: {}".format(t2.shape))
168
+ # print("t3: {}".format(t3.shape))
169
+
170
+ ret_val = y_p2 - (t1 + t2 + t3)
171
+
172
+ if fpe_example == 3:
173
+ ret_val = y_p2 - ((x + 1) * y_p1 + x ** 2 * tf.math.exp(t) * y_pp1)
174
+
175
+ if fpe_example == 4:
176
+ t1 = y * (y_pp1 * x ** 2 - 4 * y_p1 * x + 4 * y + x * x / 3.0)
177
+ t2 = y_p1 * (2 * x * y_p1 - 4 * x * y + x * x * x / 3.0)
178
+ t3 = x ** 2 * y_pp1 * y
179
+ ret_val = y_p2 * x * x - (t1 + t2 + t3)
180
+
181
+ if fpe_example == 5:
182
+ ret_val = y_p3 - (-2 * y + 3 * x * y_p1 - w * y_p2 + x ** 2 * y_pp1 + w ** 2 * y_pp2 + 2 * y_pp12)
183
+
184
+ return ret_val
185
+
186
+ """""""""""""""""""""""""""
187
+ Initial values
188
+ """""""""""""""""""""""""""
189
+ # initialize_ops are given in bottom-up order.
190
+ initialize_ops = np.zeros([2 ** n_tree_layers - 1])
191
+ # initialize_ops = ["mul", "mul", "id"]
192
+ # if fpe_example in [1, 2, 3, 5]:
193
+ # initialize_ops = ["id", "exp", "mul"]
194
+ # elif fpe_example in [4]:
195
+ # initialize_ops = ["mul", "exp", "mul"]
196
+
197
+
198
+ # initialize_ops = ["exp", "sin", "mul"]
199
+ #
200
+ min_x = 0
201
+ max_t = 5
202
+ min_t = 0
203
+ n_bc_points = 5
204
+
205
+ # Initial values for (x, y)
206
+
207
+ fixed_x = []
208
+ fixed_y = []
209
+ # for i in range(n_bc_points):
210
+ # t_i = i * (max_t - min_t)/n_bc_points + min_t
211
+ # fixed_x.append([0, t_i])
212
+ # # fixed_y.append(0)
213
+ # fixed_y.append(1 - np.exp(-1 * t_i))
214
+ # fixed_x.append([np.pi, t_i])
215
+ # fixed_y.append(np.exp(-1 * t_i) - 1)
216
+ # fixed_y.append(0)
217
+
218
+
219
+
220
+ # Initial values for (x, y')
221
+ fixed_x_p1 = []
222
+ fixed_y_p1 = []
223
+ fixed_x_p2 = []
224
+ fixed_y_p2 = []
225
+
226
+ if mode == "de":
227
+ if fpe_example != 5:
228
+ for i in range(n_bc_points):
229
+ x_i = i * (max_x - min_x) / (n_bc_points - 1) + min_x
230
+ fixed_x.append([x_i, 0])
231
+ if fpe_example in [1, 2, 5]:
232
+ fixed_y.append(x_i)
233
+ elif fpe_example == 3:
234
+ fixed_y.append(x_i + 1)
235
+ elif fpe_example == 4:
236
+ fixed_y.append(x_i ** 2)
237
+ # fixed_y.append(0)
238
+ # fixed_y.append(x_i + np.cos(x_i))
239
+ # fixed_x_p2.append([x_i, 0])
240
+ # fixed_y_p2.append(np.sin(x_i))
241
+
242
+ if fpe_example == 5:
243
+ for i in range(n_bc_points):
244
+ x_i = i * (max_x - min_x) / (n_bc_points - 1) + min_x
245
+ for j in range(n_bc_points):
246
+ w_j = j * (max_x - min_x) / (n_bc_points - 1) + min_x
247
+
248
+ fixed_x.append([x_i, w_j, 0])
249
+ fixed_y.append(x_i)
250
+
251
+ # print("IVP (x, y):\n{}".format([(fixed_x[i], fixed_y[i]) for i in range(len(fixed_x))]))
252
+ # print("IVP (x, y_p1):\n{}".format([(fixed_x_p1[i], fixed_y_p1[i]) for i in range(len(fixed_x_p1))]))
253
+ # print("IVP (x, y_p2):\n{}".format([(fixed_x_p2[i], fixed_y_p2[i]) for i in range(len(fixed_x_p2))]))
254
+
255
+ # Weight to give IVP error
256
+ ivp_lambda = 10
257
+
258
+
259
+ """""""""""""""""""""""""""
260
+ Training hyperparameters
261
+ """""""""""""""""""""""""""
262
+ quick_train_fraction = 0.7
263
+
264
+ # Probably don't need to change any of the ones below
265
+ max_training_batch_size = 1000
266
+ t1_fraction = 5/20
267
+ t2_fraction = 15 / 20
268
+
269
+ train_N = 5000
270
+ test_N = 1000
271
+
272
+ eps = 1e-4
273
+ big_eps = 1e-3
274
+ d_eps = 2.0e-2
275
+ learn_rate = 0.001
276
+ w_matrix_stddev = 0.1
277
+ init_weight_value = 5
SymbolicFunctionLearner.py ADDED
@@ -0,0 +1,1449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """""""""""""""""""""""""""""""""
2
+ Do not run or modify this file.
3
+
4
+ For running: DiffEqnSolver.py
5
+ For modifying: Settings.py
6
+ """""""""""""""""""""""""""""""""
7
+
8
+ import datetime
9
+ import time
10
+
11
+ import numpy as np
12
+ import tensorflow as tf
13
+
14
+ import DataUtils
15
+ import Settings
16
+ from DataUtils import choices_to_init_weight_matrix
17
+ from DataUtils import tf_diff_sqrt, tf_diff_log, our_tanh, spike
18
+ from Settings import implicit_function, d_eps
19
+
20
+ tf.compat.v1.disable_eager_execution()
21
+
22
+
23
+ def new_weight_matrix(n_rows, n_cols, mean=0.0, name=None):
24
+ initial = tf.random.normal(shape=[n_rows, n_cols], mean=mean, stddev=Settings.w_matrix_stddev)
25
+ if name is not None:
26
+ return tf.Variable(initial, name=name)
27
+ return tf.Variable(initial)
28
+
29
+
30
+ def new_bias(n_cols, name=None):
31
+ initial = tf.zeros(shape=[1, n_cols])
32
+ if name is not None:
33
+ return tf.Variable(initial, name=name)
34
+ return tf.Variable(initial)
35
+
36
+
37
+ def operate_on_tensors(tensor_A, tensor_B, fn_set, use_both_for_unary=True):
38
+ # print('op on tensors. input shapes: {}, {}'.format(tensor_A.shape, tensor_B.shape))
39
+ if use_both_for_unary:
40
+ w2 = 1.0
41
+ else:
42
+ w2 = 0.0
43
+
44
+ answer_vector = []
45
+ for operator_i in fn_set:
46
+ if operator_i == 'id':
47
+ answer_vector.extend([tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0]])
48
+ # print("id vector shape: {}".format(answer_vector[-1].shape))
49
+ elif operator_i == 'add':
50
+ answer_vector.extend([tensor_A[:, :, 0] + tensor_B[:, :, 0]])
51
+ elif operator_i == 'sin':
52
+ answer_vector.extend([tf.sin(tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0])])
53
+ elif operator_i == 'cos':
54
+ answer_vector.extend([tf.cos(tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0])])
55
+ elif operator_i == 'sqrt':
56
+ answer_vector.extend([tf_diff_sqrt(tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0])])
57
+ elif operator_i == 'mul':
58
+ answer_vector.extend([tf.multiply(tensor_A[:, :, 0], tensor_B[:, :, 0])])
59
+ elif operator_i == 'div':
60
+ answer_vector.extend([tf.math.divide_no_nan(tensor_A[:, :, 0], tensor_B[:, :, 0])])
61
+ elif operator_i == 'log':
62
+ answer_vector.extend([tf_diff_log(tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0])])
63
+ elif operator_i == 'exp':
64
+ answer_vector.extend([tf.exp(our_tanh(tensor_A[:, :, 0] + w2 * tensor_B[:, :, 0], factor=np.log(50000)))])
65
+ else:
66
+ answer_vector.extend([None])
67
+
68
+ return tf.stack(answer_vector, axis=-1)
69
+
70
+
71
+ def sm_no_const_selector(nonflat_input, flat_input, initial_weights):
72
+ # print("sm_no_const_selector---")
73
+ # print("initial_weights: {}".format(initial_weights.shape))
74
+ # print("nonflat_input: {}".format(nonflat_input.shape))
75
+ pre_sm_weights = new_weight_matrix(int(nonflat_input.shape[-1]), 1)
76
+ post_sm_weights = tf.math.softmax(pre_sm_weights + initial_weights, axis=0)
77
+ # print("post_sm_weights: {}".format(post_sm_weights.shape))
78
+ sm_result = tf.matmul(nonflat_input, post_sm_weights)
79
+ # print("sm_result: {}".format(sm_result.shape))
80
+
81
+ flat_weights = tf.multiply(post_sm_weights,
82
+ tf.cast(tf.greater(post_sm_weights,
83
+ tf.reduce_max(post_sm_weights) - 0.01), tf.float32))
84
+ flat_weights = tf.divide(flat_weights, tf.reduce_sum(flat_weights))
85
+ flat_result = tf.matmul(flat_input, flat_weights)
86
+
87
+ return sm_result, flat_result, pre_sm_weights+initial_weights, post_sm_weights, flat_weights
88
+
89
+
90
+ def collect_op_inputs_str(weight_w, weight_b, input_strs):
91
+ num_inputs = weight_w.shape[0]
92
+ # print("num_inputs: {}. input_strs length: {}".format(num_inputs, len(input_strs)))
93
+ # print(weight_w)
94
+ # print(input_strs)
95
+ temp_answer = ''
96
+ has_one = False
97
+ has_more_than_one = False
98
+ for row in range(num_inputs):
99
+ if np.abs(weight_w[row][0]) > Settings.big_eps and input_strs[row] != '0':
100
+ if has_one:
101
+ temp_answer += ' + '
102
+ has_more_than_one = True
103
+ if np.abs(weight_w[row][0] - 1) < Settings.big_eps:
104
+ temp_answer += '{}'.format(input_strs[row])
105
+ else:
106
+ temp_answer += '{:.4f}*({})'.format(weight_w[row][0], input_strs[row])
107
+ has_one = True
108
+ # print('weight_b[-1]: {}'.format(weight_b))
109
+ if np.abs(weight_b[-1][0]) > Settings.big_eps:
110
+ if has_one:
111
+ temp_answer += ' + '
112
+ has_more_than_one = True
113
+ temp_answer += '{:.4f}'.format(weight_b[-1][0])
114
+ if len(temp_answer) == 0:
115
+ temp_answer = '0'
116
+ if has_more_than_one:
117
+ return '(' + temp_answer + ')'
118
+ return temp_answer
119
+
120
+ def collect_minimal_op_inputs_str(weight_w, input_strs):
121
+ num_inputs = weight_w.shape[0]
122
+ temp_answer = ''
123
+ has_one = False
124
+ has_more_than_one = False
125
+ for row in range(num_inputs):
126
+ if has_one:
127
+ temp_answer += ' + '
128
+ has_more_than_one = True
129
+ temp_answer += '{}'.format(input_strs[row])
130
+ has_one = True
131
+
132
+ if len(temp_answer) == 0:
133
+ temp_answer = '0'
134
+ if has_more_than_one:
135
+ return '(' + temp_answer + ')'
136
+ return temp_answer
137
+
138
+ def operation_to_str_best(weight_w, weight_b, weight_sm, input_strs1, input_strs2, fn_set,
139
+ digits=None, unary_both=True, minimal=False):
140
+ if input_strs2 is None:
141
+ temp_answer = collect_op_inputs_str(weight_w, weight_b, input_strs1)
142
+ return [temp_answer]
143
+
144
+ answer = ['0' for _ in fn_set]
145
+
146
+ temp_answer1 = input_strs1
147
+ temp_answer2 = input_strs2
148
+
149
+ # Set up temp answer. Don't change this value!
150
+ if unary_both:
151
+ if temp_answer1 == '0' and temp_answer2 == '0':
152
+ temp_answer = '0'
153
+ elif temp_answer1 == '0':
154
+ temp_answer = str(temp_answer2)
155
+ elif temp_answer2 == '0':
156
+ temp_answer = str(temp_answer1)
157
+ else:
158
+ temp_answer = '({} + {})'.format(temp_answer1, temp_answer2)
159
+ else:
160
+ temp_answer = str(temp_answer1)
161
+
162
+ if 'id' in fn_set:
163
+ fn_index = fn_set.index('id')
164
+ answer[fn_index] = temp_answer
165
+
166
+ if 'sin' in fn_set:
167
+ fn_index = fn_set.index('sin')
168
+ if temp_answer == '0':
169
+ answer[fn_index] = '0'
170
+ else:
171
+ answer[fn_index] = 'sin({})'.format(temp_answer)
172
+
173
+ if 'cos' in fn_set:
174
+ fn_index = fn_set.index('cos')
175
+ answer[fn_index] = 'cos({})'.format(temp_answer)
176
+
177
+ if 'sqrt' in fn_set:
178
+ fn_index = fn_set.index('sqrt')
179
+ answer[fn_index] = '(abs({}))^(0.5)'.format(temp_answer)
180
+
181
+ if 'log' in fn_set:
182
+ fn_index = fn_set.index('log')
183
+ if temp_answer == '0':
184
+ answer[fn_index] = 'log(0.0001)'
185
+ else:
186
+ answer[fn_index] = 'log({})'.format(temp_answer)
187
+
188
+ if 'mul' in fn_set:
189
+ fn_index = fn_set.index('mul')
190
+ if temp_answer1 == '0' or temp_answer2 == '0':
191
+ prod_answer = '0'
192
+ else:
193
+ prod_answer = '({} * {})'.format(temp_answer1, temp_answer2)
194
+ answer[fn_index] = prod_answer
195
+
196
+ if 'add' in fn_set:
197
+ fn_index = fn_set.index('add')
198
+ if temp_answer1 == '0' and temp_answer2 == '0':
199
+ sum_answer = '0'
200
+ elif temp_answer1 == '0':
201
+ sum_answer = str(temp_answer2)
202
+ elif temp_answer2 == '0':
203
+ sum_answer = str(temp_answer1)
204
+ else:
205
+ sum_answer = '({} + {})'.format(temp_answer1, temp_answer2)
206
+ answer[fn_index] = sum_answer
207
+
208
+ if 'sub' in fn_set:
209
+ fn_index = fn_set.index('sub')
210
+ temp_answer1 = input_strs1
211
+ temp_answer2 = input_strs2
212
+
213
+ if temp_answer1 == '0' and temp_answer2 == '0':
214
+ diff_answer = '0'
215
+ elif temp_answer1 == '0':
216
+ diff_answer = "-{}".format(temp_answer2)
217
+ elif temp_answer2 == '0':
218
+ diff_answer = temp_answer1
219
+ else:
220
+ diff_answer = '({} - {})'.format(temp_answer1, temp_answer2)
221
+ answer[fn_index] = diff_answer
222
+
223
+ if 'max' in fn_set:
224
+ fn_index = fn_set.index('max')
225
+ answer[fn_index] = 'max({}, {})'.format(temp_answer1, temp_answer2)
226
+
227
+ if 'min' in fn_set:
228
+ fn_index = fn_set.index('min')
229
+ answer[fn_index] = 'min({}, {})'.format(temp_answer1, temp_answer2)
230
+
231
+ if 'div' in fn_set:
232
+ fn_index = fn_set.index('div')
233
+ if temp_answer2 == '0':
234
+ temp_answer2 = '0.001'
235
+ if temp_answer1 == '0':
236
+ div_answer = '0'
237
+ else:
238
+ div_answer = '({} / ({}))'.format(temp_answer1, temp_answer2)
239
+ answer[fn_index] = div_answer
240
+
241
+ if 'exp' in fn_set:
242
+ fn_index = fn_set.index('exp')
243
+ answer[fn_index] = 'exp({})'.format(temp_answer)
244
+
245
+ new_answer = [collect_op_inputs_str(weight_sm, np.zeros([1, 1]), answer)]
246
+ # print('New answer: {}'.format(new_answer))
247
+ # print('weight w, weight b: {}, {}'.format(weight_w, weight_b))
248
+ if minimal:
249
+ ret_val = collect_minimal_op_inputs_str(weight_w, new_answer)
250
+ else:
251
+ ret_val = collect_op_inputs_str(weight_w, weight_b, new_answer)
252
+ return ret_val
253
+
254
+
255
+ def flattened_sm_result(input_x, sm_applied_weights, our_w, our_b):
256
+ # print('Create operator node. Input shapes: {}, {}'.format(input_1.shape, input_2.shape))
257
+ new_sm_weights = tf.multiply(sm_applied_weights,
258
+ tf.cast(tf.greater(sm_applied_weights,
259
+ tf.reduce_max(sm_applied_weights) - 0.01), tf.float32))
260
+ new_sm_weights = tf.divide(new_sm_weights, tf.reduce_sum(new_sm_weights))
261
+
262
+ sm_result = tf.matmul(input_x, new_sm_weights)
263
+ final_result = tf.multiply(sm_result, our_w) + our_b
264
+ # print(' Final result shape: {}'.format(final_result.shape))
265
+
266
+ return final_result, new_sm_weights
267
+
268
+
269
+ class SFL:
270
+ def __init__(self, var_names=None):
271
+
272
+ self.name = "Symbolic Function Learner"
273
+ self.short_name = "SFL"
274
+
275
+ # mode: in ["sr", "de", "lr"]
276
+ self.mode = Settings.mode
277
+
278
+ # main hyperparameters of the symbolic expression
279
+ self.n_tree_layers = Settings.n_tree_layers
280
+ self.function_set = Settings.function_set.copy()
281
+ self.n_input_variables = Settings.num_features
282
+ self.n_dims_per_variable = Settings.num_dims_per_feature
283
+ self.n_dims_in_output = Settings.n_dims_in_output
284
+ assert self.n_dims_in_output in [1, self.n_dims_per_variable]
285
+
286
+ # use_both_for_unary: decide how to handle two input children
287
+ # for a unary operator.
288
+ # True: add the two inputs.
289
+ # False: keep first input; discard second input.
290
+ self.use_both_for_unary = Settings.use_both_for_unary
291
+
292
+ # Use a softmax on leaf layer?
293
+ self.sm_leaf_layer = Settings.use_leaf_sm
294
+
295
+ # data_x,y: Input (x, y) values over which we are training.
296
+ # For symbolic regression, it's the same as fixed_x,y.
297
+ # For differential equations, it's random values.
298
+ self.data_x = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable,
299
+ self.n_input_variables], name="data_x")
300
+ self.data_y = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable, 1], name="data_y")
301
+
302
+ # Fixed_x,y: these are the set of points that must be satisfied
303
+ # by the function that is learned. These are used to compute
304
+ # the residual error in the cost function.
305
+ self.fixed_x = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable,
306
+ self.n_input_variables], name="data_x")
307
+ self.fixed_y = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable, 1], name="data_y")
308
+
309
+ # To initialize operators in the SFL with a warm start before training
310
+ self.init_op_weights = tf.compat.v1.placeholder("float", [len(self.function_set), 2 ** self.n_tree_layers - 1],
311
+ name="init_op_weights")
312
+ self.init_op_weight_matrix = np.zeros(shape=[len(self.function_set), 2 ** self.n_tree_layers - 1])
313
+
314
+ # To initialize variable choices in the SFL with a warm start before training
315
+ num_var_input_choices = self.n_input_variables
316
+ self.init_var_weights = tf.compat.v1.placeholder("float", [num_var_input_choices, 2 ** self.n_tree_layers],
317
+ name="init_var_weights")
318
+ self.init_var_weight_matrix = np.zeros(shape=[num_var_input_choices, 2 ** self.n_tree_layers])
319
+
320
+ # variables can have default or custom names
321
+ if self.n_input_variables == 1 and var_names is None:
322
+ self.var_names = ['x']
323
+ elif var_names is None:
324
+ self.var_names = ['x{}'.format(i + 1) for i in range(self.n_input_variables)]
325
+ else:
326
+ self.var_names = var_names
327
+
328
+ self.learn_rate = Settings.learn_rate
329
+
330
+ self.y_gold = self.data_y
331
+ self.g_error = tf.Variable(0.0)
332
+ self.g_error_not_flat = tf.Variable(0.0)
333
+ self.mse = tf.Variable(0.0)
334
+ self.mse_not_flat = tf.Variable(0.0)
335
+ self.spike_error = tf.Variable(0.0)
336
+ self.ivp_error = tf.Variable(0.0)
337
+ self.ivp_error_not_flat = tf.Variable(0.0)
338
+ self.total_error = tf.Variable(0.0)
339
+
340
+ if self.mode == "de":
341
+ self.ivp_lambda = Settings.ivp_lambda
342
+ else:
343
+ self.ivp_lambda = 0
344
+
345
+ self.train_accuracy_log = []
346
+ self.valid_accuracy_log = []
347
+ self.test_accuracy_log = []
348
+
349
+ self.seen_eqns = []
350
+ self.seen_minimal_eqns = []
351
+ self.log_iters = []
352
+
353
+ self.best_accuracy_so_far = 9999999
354
+ self.best_formula_so_far = ""
355
+ self.best_iter = 0
356
+
357
+ self.y_hat = None
358
+ self.y_hat_p1 = None
359
+ self.y_hat_pp1 = None
360
+ self.y_hat_p2 = None
361
+ self.y_hat_pp2 = None
362
+ self.y_hat_p3 = None
363
+ self.y_hat_pp3 = None
364
+ self.y_hat_pp12 = None
365
+ self.implicit_g = None
366
+ self.y_hat_not_flat = None
367
+ self.y_hat_p_not_flat = None
368
+ self.y_hat_pp_not_flat = None
369
+ self.implicit_g_not_flat = None
370
+
371
+ self.W_matrices = []
372
+ self.b_matrices = []
373
+ self.non_sm_weights = []
374
+ self.leaf_sm_weights = []
375
+ self.sm_W_matrices = []
376
+ self.sm_applied_W_matrices = []
377
+ self.flattened_W_matrices = []
378
+
379
+ self.use_both_for_unary = Settings.use_both_for_unary
380
+
381
+ self.init = None
382
+ self.sess = None
383
+
384
+ self.build_sfl()
385
+ self.reset(var_names)
386
+
387
+ def build_sfl(self):
388
+ self.data_x = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable,
389
+ self.n_input_variables], name="data_x")
390
+ self.data_y = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable, 1], name="data_y")
391
+ self.fixed_x = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable,
392
+ self.n_input_variables], name="fixed_x")
393
+ self.fixed_y = tf.compat.v1.placeholder("float", [None, self.n_dims_per_variable, 1], name="fixed_y")
394
+
395
+ # To initialize operators in the SFL with a warm start before training
396
+ self.init_op_weights = tf.compat.v1.placeholder("float", [len(self.function_set), 2 ** self.n_tree_layers - 1],
397
+ name="init_op_weights")
398
+ # To initialize variable choices in the SFL with a warm start before training
399
+ # Right now, only one variable is supported.
400
+ num_var_input_choices = self.n_input_variables
401
+
402
+ self.init_var_weights = tf.compat.v1.placeholder("float", [num_var_input_choices, 2 ** self.n_tree_layers],
403
+ name="init_var_weights")
404
+
405
+ self.g_error = tf.Variable(0.0)
406
+ self.g_error_not_flat = tf.Variable(0.0)
407
+ self.mse = tf.Variable(0.0)
408
+ self.mse_not_flat = tf.Variable(0.0)
409
+ self.spike_error = tf.Variable(0.0)
410
+ self.ivp_error = tf.Variable(0.0)
411
+ self.ivp_error_not_flat = tf.Variable(0.0)
412
+ self.total_error = tf.Variable(0.0)
413
+
414
+ self.W_matrices = []
415
+ self.b_matrices = []
416
+ self.non_sm_weights = []
417
+ self.leaf_sm_weights = []
418
+ self.sm_W_matrices = []
419
+ self.sm_applied_W_matrices = []
420
+ self.flattened_W_matrices = []
421
+
422
+ previous_output = []
423
+ previous_flat_output = []
424
+ weight_layer = []
425
+ bias_layer = []
426
+
427
+ if Settings.show_output:
428
+ print("Setting up {} model.".format(self.name))
429
+ print(" {} tree layers.".format(self.n_tree_layers))
430
+ print(" {} features of {} component(s) each.".format(self.n_input_variables, self.n_dims_per_variable))
431
+ print(" {} component(s) in output.".format(self.n_dims_in_output))
432
+ print(" {} operators: {}.".format(len(self.function_set),
433
+ self.function_set))
434
+
435
+ # Set up leaf layer
436
+ for i in range(2 ** (Settings.n_tree_layers - 1)):
437
+ if self.sm_leaf_layer:
438
+ num_leaf_weights = 1
439
+ else:
440
+ num_leaf_weights = self.n_input_variables
441
+
442
+ new_weights1 = new_weight_matrix(num_leaf_weights, 1, mean=0.0)
443
+ new_b1 = new_bias(1)
444
+
445
+ new_weights2 = new_weight_matrix(num_leaf_weights, 1, mean=0.0)
446
+ new_b2 = new_bias(1)
447
+
448
+ # print("self.data_x.shape: {}".format(self.data_x.shape))
449
+
450
+ if self.sm_leaf_layer:
451
+ new_sm_weights1 = new_weight_matrix(self.n_input_variables, 1, mean=0.0)
452
+ new_sm_weights2 = new_weight_matrix(self.n_input_variables, 1, mean=0.0)
453
+
454
+ input_1 = tf.matmul(self.data_x, tf.math.softmax(new_sm_weights1, axis=0))
455
+ input_2 = tf.matmul(self.data_x, tf.math.softmax(new_sm_weights2, axis=0))
456
+
457
+ # todo: ugh
458
+ # new_weights1 = tf.constant([[1.0]])
459
+ # new_weights2 = tf.constant([[1.0]])
460
+ else:
461
+ input_1 = self.data_x
462
+ input_2 = self.data_x
463
+
464
+ # print("input_1.shape: {}".format(input_1.shape))
465
+ result_1 = tf.matmul(input_1, new_weights1) + new_b1
466
+ result_2 = tf.matmul(input_2, new_weights2) + new_b2
467
+
468
+ # print("result_1.shape: {}".format(result_1.shape))
469
+ weight_layer.extend([new_weights1, new_weights2])
470
+ bias_layer.extend([new_b1, new_b2])
471
+ if self.sm_leaf_layer:
472
+ self.leaf_sm_weights.extend([tf.math.softmax(new_sm_weights1, axis=0),
473
+ tf.math.softmax(new_sm_weights2, axis=0)])
474
+ self.non_sm_weights.extend([new_weights1, new_weights2, new_b1, new_b2])
475
+ # self.non_sm_weights.extend([new_weights1, new_weights2])
476
+
477
+ previous_output.extend([result_1, result_2])
478
+ previous_flat_output.extend([result_1, result_2])
479
+
480
+ self.W_matrices.append(weight_layer)
481
+ self.b_matrices.append(bias_layer)
482
+ self.sm_W_matrices.append([])
483
+ self.sm_applied_W_matrices.append([])
484
+ self.flattened_W_matrices.append([])
485
+ current_node = 0
486
+
487
+ # Set up parent layers, one at a time going up
488
+ for j in range(Settings.n_tree_layers):
489
+ sm_weight_layer = []
490
+ sm_applied_weight_layer = []
491
+ flattened_weight_layer = []
492
+ weight_layer = []
493
+ bias_layer = []
494
+ new_output = []
495
+ new_flat_output = []
496
+ result_layer = []
497
+ flattened_result_layer = []
498
+
499
+ for i in range(2 ** (Settings.n_tree_layers - j - 1)):
500
+ current_input_1 = previous_output[2 * i]
501
+ current_input_2 = previous_output[2 * i + 1]
502
+ nonflatten_input = operate_on_tensors(current_input_1, current_input_2, self.function_set,
503
+ use_both_for_unary=self.use_both_for_unary)
504
+
505
+ current_flat_input_1 = previous_flat_output[2 * i]
506
+ current_flat_input_2 = previous_flat_output[2 * i + 1]
507
+ flatten_input = operate_on_tensors(current_flat_input_1, current_flat_input_2,
508
+ self.function_set,
509
+ use_both_for_unary=self.use_both_for_unary)
510
+
511
+ init_op_weights = tf.reshape(self.init_op_weights[:, current_node], [-1, 1])
512
+ sm_r, flat_r, pre_sm_w, post_sm_w, flat_w = sm_no_const_selector(nonflatten_input,
513
+ flatten_input,
514
+ init_op_weights)
515
+ new_w = new_weight_matrix(1, 1, mean=1.0)
516
+ new_b = new_bias(1)
517
+ # self.non_sm_weights.extend([new_b])
518
+
519
+ sm_r = tf.math.multiply(sm_r, new_w) + new_b
520
+ flat_r = tf.multiply(flat_r, new_w) + new_b
521
+
522
+ sm_weight_layer.extend([pre_sm_w])
523
+ sm_applied_weight_layer.extend([post_sm_w])
524
+ flattened_weight_layer.extend([flat_w])
525
+
526
+ new_output.extend([sm_r])
527
+ new_flat_output.extend([flat_r])
528
+
529
+ weight_layer.extend([new_w])
530
+ bias_layer.extend([new_b])
531
+ """ self.non_sm_weights.extend([new_w, new_b])"""
532
+
533
+ result_layer.extend([sm_r])
534
+ flattened_result_layer.extend([flat_r])
535
+
536
+ current_node += 1
537
+
538
+ self.sm_W_matrices.extend([sm_weight_layer])
539
+ self.sm_applied_W_matrices.extend([sm_applied_weight_layer])
540
+ self.flattened_W_matrices.extend([flattened_weight_layer])
541
+ self.W_matrices.extend([weight_layer])
542
+ self.b_matrices.extend([bias_layer])
543
+
544
+ previous_output = new_output
545
+ previous_flat_output = new_flat_output
546
+
547
+ if self.mode == "lr":
548
+ self.y_hat_not_flat = spike(previous_output[-1])
549
+ self.y_hat = spike(previous_flat_output[-1])
550
+ else:
551
+ self.y_hat_not_flat = our_tanh(previous_output[-1], factor=10000)
552
+ self.y_hat = our_tanh(previous_flat_output[-1], factor=10000)
553
+
554
+ def reset(self, var_names=None):
555
+ tf.compat.v1.reset_default_graph()
556
+ self.build_sfl()
557
+
558
+ if var_names is not None:
559
+ self.var_names = var_names
560
+
561
+ self.log_iters = []
562
+ self.train_accuracy_log = []
563
+ self.valid_accuracy_log = []
564
+ self.test_accuracy_log = []
565
+ self.seen_eqns = []
566
+ self.seen_minimal_eqns = []
567
+
568
+ self.setup_derivative_values()
569
+ self.setup_err_values(non_const=Settings.non_const)
570
+
571
+ # TODO: really need to sort out the whole fixed_x, fixed_y thing
572
+ if self.mode == "de":
573
+ self.ivp_error_not_flat, self.ivp_error = self.setup_ivp_values(self.fixed_x, self.fixed_y)
574
+
575
+ if self.mode == "de":
576
+ self.total_error = self.total_error + self.g_error
577
+ if Settings.non_const:
578
+ self.total_error = self.total_error + self.spike_error
579
+
580
+ self.total_error = self.total_error + self.mse + self.ivp_lambda * self.ivp_error
581
+
582
+ sum_of_squares = tf.reduce_sum([tf.reduce_sum(tf.square(reg_w)) for reg_w in self.non_sm_weights])
583
+ sum_of_squares_minus_max = sum_of_squares - tf.reduce_sum([tf.reduce_max(tf.square(reg_w))
584
+ for reg_w in self.non_sm_weights])
585
+
586
+ self.regularization_penalty = tf.reduce_mean([tf.reduce_sum(tf.abs(reg_w))
587
+ for reg_w in self.non_sm_weights])
588
+
589
+ # self.regularization_penalty += sum_of_squares_minus_max
590
+
591
+ self.loss_function1 = self.mse_not_flat + self.g_error_not_flat + self.spike_error + self.ivp_lambda * self.ivp_error_not_flat
592
+
593
+ self.loss_function2 = self.mse + self.g_error + self.spike_error + self.ivp_lambda * self.ivp_error
594
+ self.loss_function2 += self.regularization_penalty * 0.05 # 0.1
595
+
596
+ self.loss_function3 = self.mse + self.g_error + self.spike_error + self.ivp_lambda * self.ivp_error
597
+ self.loss_function3 += self.regularization_penalty * 0.9 # 1.0
598
+
599
+ self.opt = tf.compat.v1.train.AdamOptimizer(self.learn_rate)
600
+
601
+ self.train_step_1 = self.opt.minimize(self.loss_function1)
602
+ self.train_step_2 = self.opt.minimize(self.loss_function2)
603
+ self.train_step_3 = self.opt.minimize(self.loss_function3)
604
+
605
+ self.init = tf.compat.v1.global_variables_initializer()
606
+ self.sess = tf.compat.v1.Session()
607
+ self.sess.run(self.init)
608
+
609
+ self.best_accuracy_so_far = 9999999
610
+ self.best_formula_so_far = ""
611
+ self.best_iter = 0
612
+
613
+ def setup_err_values(self, non_const=False):
614
+ if self.mode == "de":
615
+ self.g_error = tf.reduce_mean(tf.math.square(self.implicit_g))
616
+ self.g_not_flat = tf.reduce_mean(tf.math.square(self.implicit_g_not_flat))
617
+ else:
618
+ self.g_error = tf.Variable(0.0)
619
+ self.g_error_not_flat = tf.Variable(0.0)
620
+ self.mse = tf.reduce_mean(tf.math.squared_difference(self.y_hat, self.data_y))
621
+ self.mse_not_flat = tf.reduce_mean(tf.math.squared_difference(self.y_hat_not_flat, self.data_y))
622
+
623
+ if non_const:
624
+ self.spike_error = tf.reduce_mean(spike(self.y_hat_p1))
625
+ # tf.reduce_sum(spike(self.y_hat_p1) + spike(self.y_hat_p2) + spike(self.y_hat_p3))
626
+
627
+ def setup_ivp_values(self, fixed_x_ph, fixed_y_ph):
628
+ y_hat_err_not_flat = tf.Variable(0.0)
629
+ y_hat_err = tf.Variable(0.0)
630
+
631
+ if fixed_x_ph is not None:
632
+ y_hat_err_not_flat = tf.reduce_mean(tf.math.squared_difference(fixed_y_ph,
633
+ self.eval_formula(fixed_x_ph, flat=False)))
634
+ y_hat_err = tf.reduce_mean(tf.math.squared_difference(fixed_y_ph, self.eval_formula(fixed_x_ph)))
635
+
636
+ eye = tf.eye(self.n_input_variables)
637
+ u1 = eye[:, 0]
638
+ if Settings.fixed_x_p1 is not None and len(Settings.fixed_x_p1) > 0:
639
+ fixed_x_p1 = tf.constant(np.reshape(Settings.fixed_x_p1,
640
+ [-1, Settings.num_dims_per_feature, Settings.num_features]),
641
+ dtype="float32")
642
+ fixed_y_p1 = tf.constant(np.reshape(Settings.fixed_y_p1,
643
+ [-1, Settings.n_dims_in_output, 1]),
644
+ dtype="float32")
645
+
646
+ y_p1_fixed_hat = self.eval_formula(fixed_x_p1 + d_eps * u1 / 2)
647
+ y_p1_fixed_hat -= self.eval_formula(fixed_x_p1 - d_eps * u1 / 2)
648
+ y_p1_fixed_hat = y_p1_fixed_hat / d_eps
649
+
650
+ y_hat_err_not_flat += tf.reduce_mean(tf.math.squared_difference(fixed_y_p1, y_p1_fixed_hat))
651
+ y_hat_err += tf.reduce_mean(tf.math.squared_difference(fixed_y_p1, y_p1_fixed_hat))
652
+
653
+ if self.n_input_variables > 1:
654
+ u2 = eye[:, 1]
655
+ if Settings.fixed_x_p2 is not None and len(Settings.fixed_x_p2) > 0:
656
+ fixed_x_p2 = tf.constant(np.reshape(Settings.fixed_x_p2,
657
+ [-1, Settings.num_dims_per_feature, Settings.num_features]),
658
+ dtype="float32")
659
+ fixed_y_p2 = tf.constant(np.reshape(Settings.fixed_y_p2,
660
+ [-1, Settings.n_dims_in_output, 1]),
661
+ dtype="float32")
662
+
663
+ y_p2_fixed_hat = self.eval_formula(fixed_x_p2 + d_eps * u2 / 2)
664
+ y_p2_fixed_hat -= self.eval_formula(fixed_x_p2 - d_eps * u2 / 2)
665
+ y_p2_fixed_hat = y_p2_fixed_hat / d_eps
666
+
667
+ y_hat_err_not_flat += tf.reduce_mean(tf.math.squared_difference(fixed_y_p2, y_p2_fixed_hat))
668
+ y_hat_err += tf.reduce_mean(tf.math.squared_difference(fixed_y_p2, y_p2_fixed_hat))
669
+
670
+ return y_hat_err_not_flat, y_hat_err
671
+
672
+ def get_formula_string(self, digits=None):
673
+ eval_dict = {self.init_op_weights: self.init_op_weight_matrix,
674
+ self.init_var_weights: self.init_var_weight_matrix}
675
+
676
+ inputs = []
677
+ for i in range(len(self.W_matrices[0])):
678
+ w_matrix = self.W_matrices[0][i].eval(session=self.sess)
679
+ b_vector = self.b_matrices[0][i].eval(session=self.sess)
680
+ if self.sm_leaf_layer:
681
+ sm_vector = self.leaf_sm_weights[i].eval(session=self.sess)
682
+ print("sm_vector: {}".format(sm_vector))
683
+
684
+ new_answer = [collect_op_inputs_str(sm_vector, np.zeros([1, 1]), self.var_names)]
685
+ new_input = collect_op_inputs_str(w_matrix, b_vector, new_answer)
686
+ else:
687
+ new_input = collect_op_inputs_str(w_matrix, b_vector, self.var_names)
688
+
689
+ inputs.extend([new_input])
690
+ for layer_i in range(1, len(self.W_matrices)):
691
+ sm_applied_this_layer = self.flattened_W_matrices[layer_i]
692
+ w_this_layer = self.W_matrices[layer_i]
693
+ b_this_layer = self.b_matrices[layer_i]
694
+ new_inputs = []
695
+ for iii in range(0, len(w_this_layer)):
696
+ new_inputs.extend([operation_to_str_best(w_this_layer[iii].eval(self.sess),
697
+ b_this_layer[iii].eval(self.sess),
698
+ sm_applied_this_layer[iii].eval(session=self.sess,
699
+ feed_dict=eval_dict),
700
+ inputs[2 * iii],
701
+ inputs[2 * iii + 1],
702
+ self.function_set,
703
+ unary_both=self.use_both_for_unary)])
704
+ inputs = new_inputs
705
+
706
+ if isinstance(inputs[0], list):
707
+ return inputs[0][0]
708
+ return inputs[0]
709
+
710
+ def get_minimal_formula_string(self):
711
+ eval_dict = {self.init_op_weights: self.init_op_weight_matrix,
712
+ self.init_var_weights: self.init_var_weight_matrix}
713
+
714
+ inputs = []
715
+ for i in range(len(self.W_matrices[0])):
716
+ # w_matrix = self.W_matrices[0][i].eval(self.sess)
717
+ # inputs.extend([collect_minimal_op_inputs_str(w_matrix, self.var_names)])
718
+ inputs.append("A{}".format(i+1))
719
+
720
+ for layer_i in range(1, len(self.W_matrices)):
721
+ sm_applied_this_layer = self.flattened_W_matrices[layer_i]
722
+ w_this_layer = self.W_matrices[layer_i]
723
+
724
+ new_inputs = []
725
+ for iii in range(0, len(sm_applied_this_layer)):
726
+ new_inputs.extend([operation_to_str_best(w_this_layer[iii].eval(self.sess),
727
+ None,
728
+ sm_applied_this_layer[iii].eval(session=self.sess,
729
+ feed_dict=eval_dict),
730
+ inputs[2 * iii],
731
+ inputs[2 * iii + 1],
732
+ self.function_set,
733
+ unary_both=self.use_both_for_unary,
734
+ minimal=True)])
735
+ inputs = new_inputs
736
+
737
+ if isinstance(inputs[0], list):
738
+ return inputs[0][0]
739
+ return inputs[0]
740
+
741
+ def eval_formula(self, input_x, flat=True):
742
+ inputs = []
743
+ for i in range(len(self.W_matrices[0])):
744
+ w_matrix = self.W_matrices[0][i]
745
+ b_vector = self.b_matrices[0][i]
746
+
747
+ if self.sm_leaf_layer:
748
+ post_sm_weights = self.leaf_sm_weights[i]
749
+ sm_result = tf.matmul(input_x, post_sm_weights)
750
+ result = tf.multiply(sm_result, w_matrix) + b_vector
751
+ else:
752
+ result = tf.matmul(input_x, w_matrix) + b_vector
753
+
754
+ inputs.extend([result])
755
+
756
+ for layer_i in range(1, len(self.W_matrices)):
757
+ sm_flat_this_layer = self.flattened_W_matrices[layer_i]
758
+ sm_applied_this_layer = self.sm_applied_W_matrices[layer_i]
759
+ w_this_layer = self.W_matrices[layer_i]
760
+ b_this_layer = self.b_matrices[layer_i]
761
+ new_inputs = []
762
+
763
+ for iii in range(0, len(w_this_layer)):
764
+ post_sm_weights = sm_applied_this_layer[iii]
765
+ flat_sm_weights = sm_flat_this_layer[iii]
766
+
767
+ op_result = operate_on_tensors(inputs[2 * iii],
768
+ inputs[2 * iii + 1],
769
+ self.function_set,
770
+ use_both_for_unary=self.use_both_for_unary)
771
+
772
+ if flat:
773
+ # result, flat_sm_weights = flattened_sm_result(op_result,
774
+ # post_sm_weights,
775
+ # w_this_layer[iii],
776
+ # b_this_layer[iii])
777
+ sm_result = tf.matmul(op_result, flat_sm_weights)
778
+ else:
779
+ sm_result = tf.matmul(op_result, post_sm_weights)
780
+ result = tf.multiply(sm_result, w_this_layer[iii]) + b_this_layer[iii]
781
+ new_inputs.extend([result])
782
+
783
+ inputs = new_inputs
784
+
785
+ if self.mode == "lr":
786
+ return spike(inputs[0])
787
+ return inputs[0]
788
+
789
+ def setup_derivative_values(self):
790
+
791
+ d2_eps = 1e-2
792
+ eye = tf.eye(self.n_input_variables)
793
+ u1 = eye[:, 0]
794
+ if self.n_input_variables > 1:
795
+ u2 = eye[:, 1]
796
+ if self.n_input_variables > 2:
797
+ u3 = eye[:, 2]
798
+ # u = []
799
+ # for i in range(self.n_input_variables):
800
+ # u_i = eye[:, i]
801
+
802
+
803
+ # dy / dx1
804
+
805
+ self.y_hat_p1 = self.eval_formula(self.data_x + d_eps * u1 / 2)
806
+ self.y_hat_p1 -= self.eval_formula(self.data_x - d_eps * u1 / 2)
807
+ self.y_hat_p1 = self.y_hat_p1 / d_eps
808
+
809
+ # d^2y / dx1^2
810
+
811
+ self.y_hat_pp1 = self.eval_formula(self.data_x + d2_eps * u1)
812
+ self.y_hat_pp1 -= (2 * self.eval_formula(self.data_x))
813
+ self.y_hat_pp1 += self.eval_formula(self.data_x - d2_eps * u1)
814
+ self.y_hat_pp1 /= (d2_eps ** 2)
815
+
816
+ if self.n_input_variables > 1:
817
+ # dy / dx2
818
+
819
+ self.y_hat_p2 = self.eval_formula(self.data_x + d_eps * u2 / 2)
820
+ self.y_hat_p2 -= self.eval_formula(self.data_x - d_eps * u2 / 2)
821
+ self.y_hat_p2 = self.y_hat_p2 / d_eps
822
+
823
+ # d^2y / dx2^2
824
+
825
+ self.y_hat_pp2 = self.eval_formula(self.data_x + d2_eps * u2)
826
+ self.y_hat_pp2 -= (2 * self.eval_formula(self.data_x))
827
+ self.y_hat_pp2 += self.eval_formula(self.data_x - d2_eps * u2)
828
+ self.y_hat_pp2 /= (d2_eps ** 2)
829
+
830
+ # d^2y / dx1 dx2
831
+ self.y_hat_pp12 = self.eval_formula(self.data_x + d2_eps * (u1 + u2))
832
+ self.y_hat_pp12 -= self.eval_formula(self.data_x - d2_eps * (u1 - u2))
833
+ self.y_hat_pp12 -= self.eval_formula(self.data_x - d2_eps * (u2 - u1))
834
+ self.y_hat_pp12 -= self.eval_formula(self.data_x + d2_eps * (-u1 - u2))
835
+ self.y_hat_pp12 /= (4 * d2_eps ** 2)
836
+ else:
837
+ self.y_hat_p2 = None
838
+ self.y_hat_pp2 = None
839
+ self.y_hat_pp12 = None
840
+
841
+ if self.n_input_variables > 2:
842
+ # dy / dx2
843
+
844
+ self.y_hat_p3 = self.eval_formula(self.data_x + d_eps * u3 / 2)
845
+ self.y_hat_p3 -= self.eval_formula(self.data_x - d_eps * u3 / 2)
846
+ self.y_hat_p3 = self.y_hat_p3 / d_eps
847
+ else:
848
+ self.y_hat_p3 = None
849
+
850
+
851
+ self.y_hat_p_not_flat = self.eval_formula(self.data_x + d_eps * u1 / 2, flat=False)
852
+ self.y_hat_p_not_flat -= self.eval_formula(self.data_x - d_eps * u1 / 2, flat=False)
853
+ self.y_hat_p_not_flat = self.y_hat_p_not_flat / d_eps
854
+
855
+ self.y_hat_pp_not_flat = self.eval_formula(self.data_x + d_eps * u1, flat=False)
856
+ self.y_hat_pp_not_flat -= 2 * self.eval_formula(self.data_x, flat=False)
857
+ self.y_hat_pp_not_flat += self.eval_formula(self.data_x - d_eps * u1, flat=False)
858
+ self.y_hat_pp_not_flat = self.y_hat_pp_not_flat / d_eps ** 2
859
+
860
+ self.implicit_g = our_tanh(implicit_function(self.data_x, self.y_hat,
861
+ [self.y_hat_p1, self.y_hat_p2, self.y_hat_p3],
862
+ [self.y_hat_pp1, self.y_hat_pp2, self.y_hat_pp12]))
863
+ self.implicit_g_not_flat = our_tanh(implicit_function(self.data_x, self.y_hat_not_flat,
864
+ [self.y_hat_p_not_flat, self.y_hat_p2, self.y_hat_p3],
865
+ [self.y_hat_pp_not_flat, self.y_hat_pp2,
866
+ self.y_hat_pp12]))
867
+
868
+ """ Like reset, but does not erase records of training history.
869
+ It only restarts training from a new random initialization. """
870
+ def soft_reset(self):
871
+ self.init = tf.compat.v1.global_variables_initializer()
872
+ self.saver = tf.compat.v1.train.Saver()
873
+ self.sess = tf.compat.v1.Session()
874
+ self.sess.run(self.init)
875
+
876
+ self.best_accuracy_so_far = 9999999
877
+ self.best_formula_so_far = ""
878
+ self.best_iter = 0
879
+
880
+ # Not needed, but don't touch
881
+ def set_init_op_weight_matrix(self, init_op_weight_matrix):
882
+ self.init_op_weight_matrix = init_op_weight_matrix
883
+
884
+ # Not needed, but don't touch
885
+ def set_init_var_weight_matrix(self, init_var_weight_matrix):
886
+ self.init_var_weight_matrix = init_var_weight_matrix
887
+
888
+ # Not 100% tested
889
+ def make_y_multi_safe(self, old_y):
890
+ if isinstance(old_y, list):
891
+ new_y = np.array(old_y)
892
+ new_y.reshape([-1, self.n_dims_in_output, 1])
893
+ else:
894
+ new_y = old_y.copy()
895
+ if len(new_y.shape) == 1:
896
+ assert (self.n_dims_in_output == 1)
897
+ new_y = [[[y_value] for _ in range(self.n_dims_per_variable)] for y_value in new_y]
898
+ new_y = np.array(new_y)
899
+ elif len(new_y.shape) == 2:
900
+ assert (self.n_dims_in_output == 1)
901
+ new_y = [[y_value for _ in range(self.n_dims_per_variable)] for y_value in new_y]
902
+ new_y = np.array(new_y)
903
+ elif new_y.shape[1] < self.n_dims_per_variable:
904
+ assert (self.n_dims_in_output == 1)
905
+ new_y = [[y_value[0] for _ in range(self.n_dims_per_variable)] for y_value in new_y]
906
+ new_y = np.array(new_y)
907
+ return new_y
908
+
909
+ def get_simple_formula(self, digits=None):
910
+ full_formula = self.get_formula_string()
911
+ return DataUtils.simplify_formula(full_formula, digits=digits)
912
+
913
+ # todo: want total or mean square error?
914
+ def test(self, x, y=None):
915
+ test_dict = {self.data_x: x,
916
+ self.init_op_weights: self.init_op_weight_matrix,
917
+ self.init_var_weights: self.init_var_weight_matrix}
918
+ if y is not None:
919
+ test_dict[self.data_y] = y
920
+ return self.sess.run(self.total_error, feed_dict=test_dict)
921
+
922
+ # Runs train process a number of times on a limited number of train steps.
923
+ # Returns the best formula found during that experience.
924
+ # If init_ops is given, it will start off with ops initialized accordingly.
925
+ # If it is None, then ops will be initialized randomly.
926
+ # If it is 0, then ops will have no initialization.
927
+ # Same with init_vars.
928
+ def train(self, x, y=None, init_op_weight_matrix=None, init_var_weight_matrix=None,
929
+ test_x=None, test_y=None):
930
+ n_rounds = Settings.num_train_steps_in_repeat_mode
931
+
932
+ batch_size = min(Settings.max_training_batch_size, int(len(x) / 2))
933
+
934
+ train_set_size = len(x)
935
+ train_x = np.array(x, dtype=np.float32)
936
+
937
+ if self.mode in ["de"]:
938
+ y = [0 for _ in range(x.shape[0])]
939
+ if test_x is not None:
940
+ test_y = [0 for _ in range(test_x.shape[0])]
941
+ # elif self.mode == ["sr", "lr"]:
942
+ # y = DataUtils.true_function(x)
943
+ # if test_x is not None:
944
+ # test_y = DataUtils.true_function(test_x)
945
+
946
+ train_y = self.make_y_multi_safe(y)
947
+
948
+ if test_y is not None:
949
+ test_y = self.make_y_multi_safe(test_y)
950
+
951
+ if init_op_weight_matrix is not None:
952
+ self.set_init_op_weight_matrix(init_op_weight_matrix)
953
+
954
+ if init_var_weight_matrix is not None:
955
+ self.set_init_var_weight_matrix(init_var_weight_matrix)
956
+
957
+ target_y = self.y_hat
958
+ show_gt = False
959
+
960
+ if Settings.show_output:
961
+ print("Starting actual training!")
962
+ start_time = time.time()
963
+ old_time = time.time()
964
+ time_spent_training = 0
965
+ time_getting_formulas = 0
966
+ time_getting_scores = 0
967
+ time_plotting = 0
968
+ other_time = 0
969
+
970
+ for i in range(1, n_rounds + 1):
971
+ mini_start_time = time.time()
972
+ train_batch_x, train_batch_y, valid_batch_x, valid_batch_y = DataUtils.get_samples(train_set_size,
973
+ batch_size,
974
+ train_x, train_y)
975
+ other_time += time.time() - mini_start_time
976
+
977
+ training_dict = {self.data_x: train_batch_x,
978
+ self.data_y: train_batch_y,
979
+ self.init_op_weights: self.init_op_weight_matrix,
980
+ self.init_var_weights: self.init_var_weight_matrix}
981
+
982
+ valid_batch_dict = {self.data_x: valid_batch_x,
983
+ self.data_y: valid_batch_y,
984
+ self.init_op_weights: self.init_op_weight_matrix,
985
+ self.init_var_weights: self.init_var_weight_matrix}
986
+
987
+ test_dict = {self.data_x: test_x, self.data_y: test_y,
988
+ self.init_op_weights: self.init_op_weight_matrix,
989
+ self.init_var_weights: self.init_var_weight_matrix}
990
+
991
+ """ Actual training happens here """
992
+ mini_start_time = time.time()
993
+ if i < n_rounds * Settings.t1_fraction:
994
+ self.sess.run(self.train_step_1, feed_dict=training_dict)
995
+ elif i < n_rounds * Settings.t2_fraction:
996
+ self.sess.run(self.train_step_2, feed_dict=training_dict)
997
+ else:
998
+ self.sess.run(self.train_step_3, feed_dict=training_dict)
999
+
1000
+ time_spent_training += (time.time() - mini_start_time)
1001
+
1002
+ """ Save formulas, accuracy, etc. """
1003
+ if (i % Settings.plot_frequency == 0 or i % Settings.output_freq == 0) and Settings.keep_logs:
1004
+
1005
+ # Save current formula to make list of all formulas seen
1006
+ current_formula = "(Formula not saved)"
1007
+ if Settings.save_all_formulas:
1008
+ mini_start_time = time.time()
1009
+ current_formula = self.get_simple_formula(digits=4)
1010
+ time_getting_formulas += (time.time() - mini_start_time)
1011
+
1012
+ if current_formula not in self.seen_eqns:
1013
+ self.seen_eqns.append(current_formula)
1014
+
1015
+ # Get results from validation set.
1016
+ mini_start_time = time.time()
1017
+ [valid_acc, y_pr_v] = self.sess.run([self.total_error, target_y], feed_dict=valid_batch_dict)
1018
+ # Get results from test set.
1019
+ if test_x is not None:
1020
+ [test_acc, y_pr_test] = self.sess.run([self.total_error, target_y], feed_dict=test_dict)
1021
+
1022
+ y_gold_v = valid_batch_y.reshape([-1, self.n_dims_per_variable, 1])[0].tolist()
1023
+ y_hat_v = y_pr_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1024
+
1025
+ time_getting_scores += (time.time() - mini_start_time)
1026
+
1027
+ mini_start_time = time.time()
1028
+ [valid_acc, g_pr_v] = self.sess.run([self.total_error, self.implicit_g], feed_dict=valid_batch_dict)
1029
+ g_hat_val = g_pr_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1030
+ g_hat_1d_val = [y_value[0][0] for y_value in g_hat_val]
1031
+ g_tru_1d_val = [y_value[0][0] for y_value in valid_batch_y]
1032
+ g_hat_1d_test = None
1033
+ g_tru_1d_test = None
1034
+
1035
+ [yp_v, ypp_v] = self.sess.run([self.y_hat_p1, self.y_hat_pp1], feed_dict=valid_batch_dict)
1036
+ y_p1_v = yp_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1037
+ y_pp1_v = ypp_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1038
+
1039
+ [yp2_v, ypp2_v] = self.sess.run([self.y_hat_p2, self.y_hat_pp2], feed_dict=valid_batch_dict)
1040
+ y_p2_v = yp2_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1041
+ y_pp2_v = ypp2_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1042
+
1043
+ time_getting_scores += (time.time() - mini_start_time)
1044
+
1045
+ if test_x is not None:
1046
+ mini_start_time = time.time()
1047
+ [test_acc, g_pr_test] = self.sess.run([self.total_error, self.implicit_g], feed_dict=test_dict)
1048
+
1049
+ g_hat_test = g_pr_test.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1050
+ g_hat_1d_test = [g_value[0][0] for g_value in g_hat_test]
1051
+ g_tru_1d_test = [g_value[0][0] for g_value in test_y]
1052
+ time_getting_scores += (time.time() - mini_start_time)
1053
+
1054
+ # Update best formula seen based on validation error.
1055
+ if Settings.save_all_formulas:
1056
+ if valid_acc < self.best_accuracy_so_far:
1057
+ self.best_accuracy_so_far = valid_acc
1058
+ self.best_formula_so_far = current_formula
1059
+ self.best_iter = i
1060
+
1061
+ # We only can make plots using y values if y is 1d.
1062
+ if self.n_dims_in_output == 1:
1063
+
1064
+ mini_start_time = time.time()
1065
+
1066
+ y_hat_1d_val = [y_value[0][0] for y_value in y_hat_v]
1067
+ y_tru_1d_val = [y_value[0][0] for y_value in valid_batch_y]
1068
+ y_hat_1d_test = None
1069
+ y_tru_1d_test = None
1070
+
1071
+ if test_x is not None:
1072
+ y_hat_test = y_pr_test.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1073
+ y_hat_1d_test = [y_value[0][0] for y_value in y_hat_test]
1074
+ y_tru_1d_test = [y_value[0][0] for y_value in test_y]
1075
+ other_time += (time.time() - mini_start_time)
1076
+
1077
+ if self.mode in ["sr", "lr"]:
1078
+ # Plot predicted y value against actual y value.
1079
+ mini_start_time = time.time()
1080
+ DataUtils.plot_predicted_vs_actual(y_hat_1d_val, y_tru_1d_val,
1081
+ y_hat_1d_test, y_tru_1d_test,
1082
+ self.name,
1083
+ set_name="Iteration {}".format(i))
1084
+ time_plotting += (time.time() - mini_start_time)
1085
+
1086
+ # DataUtils.plot_2d_curve(x_1d_val, y_tru_1d_val, y_hat_1d_val, None, None, None)
1087
+
1088
+ # If x is also 1d, we can plot the function itself.
1089
+ if self.n_input_variables == 1:
1090
+
1091
+ # Plot the actual function we learned.
1092
+ mini_start_time = time.time()
1093
+ x_1d_val = [x_value[0][0] for x_value in valid_batch_x]
1094
+ x_1d_test = None
1095
+ if test_x is not None:
1096
+ x_1d_test = [x_value[0][0] for x_value in test_x]
1097
+ other_time += (time.time() - mini_start_time)
1098
+
1099
+ mini_start_time = time.time()
1100
+ DataUtils.plot_1d_curve(x_1d_val, y_tru_1d_val, y_hat_1d_val,
1101
+ x_1d_test, y_tru_1d_test, y_hat_1d_test,
1102
+ file_suffix="_y",
1103
+ title="Learned function: Iteration {}".format(i),
1104
+ show_ground_truth=show_gt)
1105
+ time_plotting += (time.time() - mini_start_time)
1106
+
1107
+ # Plot the g output values, in implicit case
1108
+ if test_x is not None:
1109
+ mini_start_time = time.time()
1110
+ DataUtils.plot_1d_curve(x_1d_val, g_tru_1d_val, g_hat_1d_val,
1111
+ x_1d_test, g_tru_1d_test, g_hat_1d_test,
1112
+ file_suffix="_g",
1113
+ title="Output of g: Iteration {}".format(i))
1114
+
1115
+ time_plotting += time.time() - mini_start_time
1116
+
1117
+ elif self.n_input_variables == 2:
1118
+ # Plot the actual function we learned.
1119
+ mini_start_time = time.time()
1120
+
1121
+ plot2d_x1 = np.arange(Settings.test_scope[0], Settings.test_scope[1], 0.1)
1122
+ plot2d_x2 = np.arange(Settings.test_scope[0], Settings.test_scope[1], 0.1)
1123
+
1124
+ plot2d_x1_m, plot2d_x2_m = np.meshgrid(plot2d_x1, plot2d_x2)
1125
+ plot2d_x1 = np.reshape(plot2d_x1_m, [-1, 1, 1])
1126
+ plot2d_x2 = np.reshape(plot2d_x2_m, [-1, 1, 1])
1127
+ plot2d_x1x2 = np.concatenate([plot2d_x1, plot2d_x2], axis=-1)
1128
+ [plot2d_y, plot2d_g] = self.sess.run([target_y, self.implicit_g],
1129
+ feed_dict={self.data_x: plot2d_x1x2,
1130
+ self.init_op_weights: self.init_op_weight_matrix,
1131
+ self.init_var_weights: self.init_var_weight_matrix})
1132
+
1133
+ if self.mode == "sr":
1134
+ plot2d_g = DataUtils.true_function(plot2d_x1x2)
1135
+
1136
+ plot2d_y_m = np.reshape(plot2d_y, plot2d_x1_m.shape)
1137
+ plot2d_g_m = np.reshape(plot2d_g, plot2d_x1_m.shape)
1138
+
1139
+ DataUtils.plot_2d_curve(plot2d_x1_m, plot2d_x2_m, plot2d_y_m, plot2d_g_m)
1140
+
1141
+ time_plotting += (time.time() - mini_start_time)
1142
+
1143
+ if Settings.keep_logs:
1144
+ mini_start_time = time.time()
1145
+ self.train_accuracy_log.append(self.test(train_x, train_y))
1146
+ # self.valid_accuracy_log.append(valid_acc)
1147
+ self.valid_accuracy_log.append(self.test(valid_batch_x, valid_batch_y))
1148
+
1149
+ # self.log_iters.append(i)
1150
+ if len(self.log_iters) == 0:
1151
+ self.log_iters.append(i)
1152
+ else:
1153
+ self.log_iters.append(self.log_iters[-1] + Settings.plot_frequency)
1154
+
1155
+ accuracies_to_plot = [self.train_accuracy_log,
1156
+ self.valid_accuracy_log]
1157
+ accuracy_type_names = ["Training Error", "Validation Error"]
1158
+ if test_x is not None:
1159
+ self.test_accuracy_log.append(test_acc)
1160
+ accuracies_to_plot.append(self.test_accuracy_log)
1161
+ accuracy_type_names.append("Test Error")
1162
+
1163
+ time_getting_scores += (time.time() - mini_start_time)
1164
+
1165
+ mini_start_time = time.time()
1166
+ DataUtils.plot_accuracy_over_time(self.log_iters, accuracies_to_plot, accuracy_type_names)
1167
+
1168
+ time_plotting += time.time() - mini_start_time
1169
+
1170
+ if i % Settings.output_freq == 0 and Settings.show_output:
1171
+
1172
+ if not Settings.keep_logs:
1173
+ # Get results from validation set.
1174
+ mini_start_time = time.time()
1175
+ [valid_acc, y_pr_v] = self.sess.run([self.total_error, target_y], feed_dict=valid_batch_dict)
1176
+ # Get results from test set.
1177
+ if test_x is not None:
1178
+ [test_acc, y_pr_test] = self.sess.run([self.total_error, target_y], feed_dict=test_dict)
1179
+ y_hat_v = y_pr_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1180
+
1181
+ g_pr_v = self.sess.run(self.implicit_g, feed_dict=valid_batch_dict)
1182
+ g_hat_val = g_pr_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1183
+
1184
+ [yp1_v, ypp1_v] = self.sess.run([self.y_hat_p1, self.y_hat_pp1],
1185
+ feed_dict={self.data_x: valid_batch_x,
1186
+ self.init_op_weights: self.init_op_weight_matrix,
1187
+ self.init_var_weights: self.init_var_weight_matrix})
1188
+ y_p1_v = yp1_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1189
+ y_pp1_v = ypp1_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1190
+
1191
+ [yp2_v, ypp2_v] = self.sess.run([self.y_hat_p2, self.y_hat_pp2],
1192
+ feed_dict={self.data_x: valid_batch_x,
1193
+ self.init_op_weights: self.init_op_weight_matrix,
1194
+ self.init_var_weights: self.init_var_weight_matrix})
1195
+ y_p2_v = yp2_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1196
+ y_pp2_v = ypp2_v.reshape([-1, self.n_dims_per_variable, 1]).tolist()
1197
+
1198
+ time_getting_scores += (time.time() - mini_start_time)
1199
+
1200
+ print()
1201
+
1202
+ print('Iteration {}:'.format(i))
1203
+
1204
+ mini_start_time = time.time()
1205
+ formula_as_string = self.get_formula_string(digits=4)
1206
+ dotdot = ""
1207
+ if len(formula_as_string) > Settings.max_formula_output_length:
1208
+ dotdot = " ..."
1209
+ print("# Current Model: {}{}".format(formula_as_string[:Settings.max_formula_output_length], dotdot))
1210
+
1211
+ simple_formula = self.get_simple_formula(digits=4)
1212
+ dotdot = ""
1213
+ if len(simple_formula) > Settings.max_formula_output_length:
1214
+ dotdot = " ..."
1215
+ print("# AKA: {}{}".format(simple_formula[:Settings.max_formula_output_length], dotdot))
1216
+
1217
+ minimal_eqn = self.get_minimal_formula_string()
1218
+ print("# Simple: {}".format(minimal_eqn))
1219
+ if minimal_eqn not in self.seen_minimal_eqns:
1220
+ self.seen_minimal_eqns.append(minimal_eqn)
1221
+
1222
+ if "**" in simple_formula:
1223
+ print("(Has a power)")
1224
+
1225
+ time_getting_formulas += (time.time() - mini_start_time)
1226
+
1227
+ print(
1228
+ " Length: {} ({})".format(len(formula_as_string), len("{}".format(simple_formula))))
1229
+
1230
+ print(" Train batch size: {}".format(train_batch_x.shape))
1231
+ print(" Valid batch size: {}".format(valid_batch_x.shape))
1232
+ print(" # Mnml eqns seen: {}".format(len(self.seen_minimal_eqns)))
1233
+
1234
+ iters_per_min = Settings.output_freq * 60 / (time.time() - old_time)
1235
+ print(' Iters per minute: {:.2f}'.format(iters_per_min))
1236
+ total_time = time.time() - start_time
1237
+ print(' Time so far: {:.2f} minutes'.format(total_time / 60.0))
1238
+ print(' ({:.1%} training, {:.1%} scoring, {:.1%} formulas)'.format(
1239
+ time_spent_training / total_time,
1240
+ time_getting_scores / total_time,
1241
+ time_getting_formulas / total_time))
1242
+ print(' ({:.1%} plotting, {:.1%} other)'.format(time_plotting / total_time,
1243
+ other_time / total_time))
1244
+ print(' Est. time left: {:.2f} minutes'.format((n_rounds - i) / iters_per_min))
1245
+
1246
+ print('Error values:')
1247
+ mini_start_time = time.time()
1248
+
1249
+ curr_errs = self.sess.run([self.g_error, self.ivp_error,
1250
+ self.spike_error, self.total_error],
1251
+ feed_dict=valid_batch_dict)
1252
+ if self.mode == "de":
1253
+ print(' g-err Valid: {}'.format(curr_errs[0]))
1254
+ print(' IVP Valid: {}'.format(curr_errs[1]))
1255
+ if Settings.non_const:
1256
+ print(' Spike err: {}'.format(curr_errs[2]))
1257
+ print(' Tot. Val.: {}'.format(curr_errs[3]))
1258
+ if np.abs(curr_errs[3] - (curr_errs[0] + self.ivp_lambda * curr_errs[1] + curr_errs[2])) > 1e-4:
1259
+ print("Something is wrong.")
1260
+
1261
+
1262
+ # Hope we don't get nans, but break out if we do.
1263
+ nans = np.isnan(curr_errs[0])
1264
+ if nans:
1265
+ break
1266
+
1267
+ if test_x is not None:
1268
+ print(' Tot. Test: {}'.format(test_acc))
1269
+
1270
+ time_getting_scores += (time.time() - mini_start_time)
1271
+
1272
+ print('Performance on sample validation data:')
1273
+
1274
+ print_str = ""
1275
+ for feature_i in range(Settings.num_features):
1276
+ print_str += "{}\t\t".format(self.var_names[feature_i])
1277
+ print_str += "|\t"
1278
+ # print_str += "y_tru\t"
1279
+ if self.mode == "de":
1280
+ print_str += "g_hat\t"
1281
+ elif self.mode == "sr" or self.mode == "lr":
1282
+ print_str += "y_tru\t"
1283
+ print_str += "y_hat\t"
1284
+
1285
+ if self.mode == "de":
1286
+ print_str += "y_p1\t"
1287
+ print_str += "y_pp1\t"
1288
+ print_str += "y_p2\t"
1289
+ print_str += "y_pp2\t"
1290
+ print(print_str)
1291
+ line_len = len(print_str) + 16
1292
+ print("=" * line_len)
1293
+
1294
+ var_range = range(self.n_input_variables)
1295
+ num_pts_to_show = 5
1296
+ if self.mode in ["sr", "lr"]:
1297
+ y_tru_v = valid_batch_y[:num_pts_to_show, :, :]
1298
+ # y_tru_v = DataUtils.predict_from_formula(Settings.true_eqn, valid_batch_x[:num_pts_to_show, :, :])
1299
+
1300
+ for datapoint_i in range(min(valid_batch_x.shape[0], num_pts_to_show)):
1301
+ comps_to_show = range(self.n_dims_per_variable)
1302
+ if self.n_dims_per_variable > 9:
1303
+ comps_to_show = [0, 1, 2, -1]
1304
+ for component_j in comps_to_show:
1305
+ if component_j == -1:
1306
+ print(" ... ")
1307
+ print_str = ""
1308
+ for var_k in var_range:
1309
+ x_ijk = valid_batch_x[datapoint_i, component_j, var_k]
1310
+ print_str += "{:.3f}\t".format(x_ijk)
1311
+ print_str += "|\t"
1312
+ # print_str += "{:.3f}\t".format(valid_batch_y[datapoint_i, component_j, 0])
1313
+
1314
+ if self.mode == "de":
1315
+ print_str += "{:.3f}\t".format(g_hat_val[datapoint_i][component_j][0])
1316
+ elif self.mode in ["sr", "lr"]:
1317
+ print_str += "{:.3f}\t".format(y_tru_v[datapoint_i][0][0])
1318
+
1319
+ print_str += "{:.3f}\t".format(y_hat_v[datapoint_i][component_j][0])
1320
+
1321
+ if self.mode == "de":
1322
+ print_str += "{:.3f}\t".format(y_p1_v[datapoint_i][component_j][0])
1323
+ print_str += "{:.3f}\t".format(y_pp1_v[datapoint_i][component_j][0])
1324
+ print_str += "{:.3f}\t".format(y_p2_v[datapoint_i][component_j][0])
1325
+ print_str += "{:.3f}\t".format(y_pp2_v[datapoint_i][component_j][0])
1326
+
1327
+ print(print_str)
1328
+ print("-" * line_len)
1329
+ print()
1330
+
1331
+ old_time = time.time()
1332
+
1333
+ if Settings.show_output:
1334
+ print('Finished training at {:%H:%M:%S}.\n'.format(datetime.datetime.now()))
1335
+ end_time = time.time()
1336
+ total_time = end_time - start_time
1337
+
1338
+ print('Took {:.2f} seconds to finish.'.format(total_time))
1339
+ print(' ({:.1%} training, {:.1%} scoring, {:.1%} formulas)'.format(time_spent_training / total_time,
1340
+ time_getting_scores / total_time,
1341
+ time_getting_formulas / total_time))
1342
+ print(' ({:.1%} plotting, {:.1%} other)'.format(time_plotting / total_time,
1343
+ other_time / total_time))
1344
+ print('Average of {:.2f} training steps per minute.'.format(
1345
+ 60 * n_rounds / total_time))
1346
+ print('Average of {:.2f} minutes per 10000 training steps.'.format(
1347
+ 10000 * total_time / (60 * n_rounds)))
1348
+
1349
+ print()
1350
+ if Settings.save_all_formulas:
1351
+ print("Best formula had accuracy {:.3f} and was seen at iteration {}:".format(
1352
+ self.best_accuracy_so_far,
1353
+ self.best_iter))
1354
+ print("{}".format(self.best_formula_so_far)[:1000])
1355
+ else:
1356
+ final_acc = self.sess.run(self.total_error, feed_dict={self.data_x: train_x,
1357
+ self.data_y: train_y,
1358
+ self.init_op_weights: self.init_op_weight_matrix,
1359
+ self.init_var_weights: self.init_var_weight_matrix})
1360
+ print("Final formula had accuracy {:.3f}:".format(final_acc))
1361
+
1362
+ print("{}".format(self.get_simple_formula(digits=4))[:1000])
1363
+ print()
1364
+
1365
+ return self.get_simple_formula(digits=4)
1366
+
1367
+ def repeat_train(self, x, y=None,
1368
+ num_repeats=Settings.num_train_repeat_processes,
1369
+ test_x=None, test_y=None,
1370
+ verbose=True):
1371
+
1372
+ # we still reduce train set size if only 1 repeat
1373
+ train_set_size = int(len(x) * Settings.quick_train_fraction + 0.1)
1374
+
1375
+ x = np.array(x)
1376
+
1377
+ if y is not None:
1378
+ y = np.array(y)
1379
+
1380
+ sample = np.random.choice(range(x.shape[0]), size=train_set_size, replace=False)
1381
+ train_x = x[sample][:]
1382
+ if y is not None:
1383
+ train_y = y[sample]
1384
+
1385
+ out_sample = [aaa for aaa in range(x.shape[0]) if aaa not in sample]
1386
+ valid_x = x[out_sample][:]
1387
+ if y is not None:
1388
+ valid_y = y[out_sample]
1389
+ valid_y = self.make_y_multi_safe(valid_y)
1390
+
1391
+ best_formula = ""
1392
+ best_iter = 0
1393
+ best_validation = 999999
1394
+ best_err = 999999
1395
+ old_time = time.time()
1396
+
1397
+ if verbose:
1398
+ print("Beginning {} repeat sessions of {} iterations each.".format(num_repeats,
1399
+ Settings.num_train_steps_in_repeat_mode))
1400
+ print()
1401
+ start_time = time.time()
1402
+ old_time = start_time
1403
+
1404
+ for train_iter in range(1, 1 + num_repeats):
1405
+ if verbose:
1406
+ print("Repeated train session {} of {}.".format(train_iter, num_repeats))
1407
+
1408
+
1409
+ self.soft_reset()
1410
+
1411
+ self.set_init_op_weight_matrix(choices_to_init_weight_matrix(Settings.initialize_ops,
1412
+ self.function_set))
1413
+ self.set_init_var_weight_matrix(choices_to_init_weight_matrix(np.zeros([2 ** self.n_tree_layers]),
1414
+ self.var_names))
1415
+
1416
+
1417
+ self.train(train_x, train_y, test_x=test_x, test_y=test_y)
1418
+
1419
+ valid_err = self.test(valid_x, valid_y)
1420
+
1421
+ current_time = time.time()
1422
+ if verbose:
1423
+ # print(self.get_simple_formula())
1424
+ print("Attained validation error: {:.5f}".format(valid_err))
1425
+
1426
+ if valid_err < best_validation:
1427
+ best_validation = valid_err
1428
+ best_formula = self.get_simple_formula()
1429
+ best_iter = train_iter
1430
+ if test_x is not None:
1431
+ safe_test_y = self.make_y_multi_safe(test_y)
1432
+ best_err = self.test(test_x, safe_test_y)
1433
+ else:
1434
+ best_err = valid_err
1435
+ if verbose:
1436
+ print(">>> New best model!")
1437
+ print(best_formula)
1438
+
1439
+ if verbose:
1440
+ iters_per_minute = 60.0 / (current_time - old_time)
1441
+ print("Took {:.2f} minutes.".format((current_time - old_time) / 60))
1442
+ print("Est. {:.2f} minutes remaining.".format((num_repeats - train_iter) / iters_per_minute))
1443
+ print()
1444
+ old_time = current_time
1445
+
1446
+ if verbose:
1447
+ print("Total time for repeat process: {:.2f} minutes.".format((time.time() - start_time) / 60))
1448
+
1449
+ return best_formula, best_iter, best_err
gp_model.py ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+ import numpy as np
4
+ from gplearn.genetic import SymbolicRegressor
5
+ from sklearn.utils.validation import column_or_1d
6
+
7
+ import Settings as settings
8
+ from DataUtils import make_y_multi_safe
9
+
10
+ pop_size = 5000
11
+ generations = 20
12
+ p_crossover = 0.7
13
+ warm_start = False
14
+
15
+
16
+ class Genetic_Model:
17
+ def __init__(self):
18
+ self.name = "Genetic Model"
19
+ self.short_name = "GP"
20
+ self.function_set = settings.function_set.copy()
21
+ if "id" in self.function_set:
22
+ self.function_set.remove("id")
23
+
24
+ self.est_gp = SymbolicRegressor(population_size=pop_size,
25
+ generations=generations, stopping_criteria=0.01, # 20 gen
26
+ p_crossover=p_crossover, p_subtree_mutation=0.1,
27
+ p_hoist_mutation=0.05, p_point_mutation=0.1,
28
+ warm_start=warm_start,
29
+ max_samples=0.9, verbose=False,
30
+ parsimony_coefficient=0.01,
31
+ function_set=self.function_set)
32
+
33
+ def reset(self):
34
+ del self.est_gp
35
+ self.est_gp = SymbolicRegressor(population_size=pop_size,
36
+ generations=generations, stopping_criteria=0.01, # 20 gen
37
+ p_crossover=p_crossover, p_subtree_mutation=0.1,
38
+ p_hoist_mutation=0.05, p_point_mutation=0.1,
39
+ warm_start=warm_start,
40
+ max_samples=0.9, verbose=False,
41
+ parsimony_coefficient=0.01,
42
+ function_set=self.function_set)
43
+
44
+ def soft_reset(self):
45
+ del self.est_gp
46
+ self.est_gp = SymbolicRegressor(population_size=pop_size,
47
+ generations=generations, stopping_criteria=0.01, # 20 gen
48
+ p_crossover=p_crossover, p_subtree_mutation=0.1,
49
+ p_hoist_mutation=0.05, p_point_mutation=0.1,
50
+ warm_start=warm_start,
51
+ max_samples=0.9, verbose=False,
52
+ parsimony_coefficient=0.01,
53
+ function_set=self.function_set)
54
+
55
+ def predict(self, X):
56
+ return self.est_gp.predict(X)
57
+
58
+ def get_formula(self):
59
+ return self.est_gp._program
60
+
61
+ def get_simple_formula(self, digits=None):
62
+ return self.get_formula()
63
+
64
+ def get_big_formula(self):
65
+ formula_string = str(self.get_formula())
66
+ nested_list_string = formula_string.replace("sqrt(", "[\'sqrt\', ")
67
+ nested_list_string = nested_list_string.replace("add(", "[\'+\', ")
68
+ nested_list_string = nested_list_string.replace("mul(", "[\'*\', ")
69
+ nested_list_string = nested_list_string.replace("sub(", "[\'-\', ")
70
+ nested_list_string = nested_list_string.replace("sin(", "[\'sin\', ")
71
+ nested_list_string = nested_list_string.replace(")", "]")
72
+ nested_list_string = nested_list_string.replace("X", "Y")
73
+
74
+ retval = ""
75
+ currently_digits = False
76
+ current_number = ""
77
+ for current_char in nested_list_string:
78
+ if current_char == 'Y':
79
+ retval += "\'x"
80
+ currently_digits = True
81
+ current_number = ""
82
+ elif currently_digits:
83
+ if current_char.isdigit():
84
+ # retval += "{}".format(current_char)
85
+ current_number += "{}".format(current_char)
86
+ else:
87
+ currently_digits = False
88
+ retval += "{}".format(int(current_number) + 1)
89
+ retval += "\'{}".format(current_char)
90
+ else:
91
+ retval += "{}".format(current_char)
92
+
93
+ if "Y" in retval:
94
+ print("ERROR: formula still contains a Y...")
95
+ print(" formula string: {}\n nested list string: {}".format(formula_string, nested_list_string))
96
+
97
+ return eval(retval)
98
+
99
+ def train(self, X, Y):
100
+ X = np.reshape(X, [X.shape[0], -1])
101
+ Y = np.reshape(Y, [-1, 1])
102
+ Y = column_or_1d(Y)
103
+ self.est_gp.fit(X, Y)
104
+ return None
105
+
106
+ # Does not repeat train. Sorry.
107
+ def repeat_train(self, x, y, test_x=None, test_y=None,
108
+ num_repeats=settings.num_train_repeat_processes,
109
+ num_steps_to_train=settings.num_train_steps_in_repeat_mode,
110
+ verbose=True):
111
+ train_set_size = int(len(x) * settings.quick_train_fraction + 0.1)
112
+ x = np.array(x)
113
+ y = np.reshape(np.array(y), [-1, ])
114
+ sample = np.random.choice(range(x.shape[0]), size=train_set_size, replace=False)
115
+ out_sample = [yyy for yyy in range(x.shape[0]) if yyy not in sample]
116
+
117
+ train_x = x[sample][:]
118
+ train_y = y[sample][:]
119
+ valid_x = x[out_sample][:]
120
+ valid_y = y[out_sample][:]
121
+
122
+ old_time = time.time()
123
+
124
+ if verbose:
125
+ print("Beginning {} repeat sessions of {} iterations each.".format(num_repeats,
126
+ settings.num_train_steps_in_repeat_mode))
127
+ print()
128
+ start_time = time.time()
129
+ old_time = start_time
130
+
131
+ self.soft_reset()
132
+ self.train(train_x, train_y)
133
+
134
+ current_time = time.time()
135
+ if verbose:
136
+ # print(self.get_simple_formula())
137
+ print("Attained validation error: {:.5f}".format(valid_err))
138
+
139
+ best_formula = self.get_simple_formula()
140
+ if test_x is not None:
141
+ safe_test_y = make_y_multi_safe(test_y)
142
+ best_err = self.test(test_x, safe_test_y)
143
+ else:
144
+ best_err = self.test(valid_x, valid_y)
145
+
146
+ if verbose:
147
+ iters_per_minute = 60.0 / (current_time - old_time)
148
+ print("Took {:.2f} minutes.".format((current_time - old_time) / 60))
149
+ print("Est. {:.2f} minutes remaining.".format((num_repeats - train_iter) / iters_per_minute))
150
+ print()
151
+
152
+ return best_formula, 0, best_err
153
+
154
+ # Mean square error
155
+ def test(self, x, y):
156
+ x = np.reshape(x, [x.shape[0], -1])
157
+ y_hat = np.reshape(self.est_gp.predict(x), [1, -1])[0]
158
+ y_gold = np.reshape(y, [1, -1])[0]
159
+ our_sum = 0
160
+ for i in range(len(y_gold)):
161
+ our_sum += (y_hat[i] - y_gold[i]) ** 2
162
+
163
+ return our_sum / len(y_gold)