Skip to content

Commit 21299af

Browse files
committed
Rewrote all modules to conform to PEP 8
1 parent b568f6f commit 21299af

File tree

7 files changed

+373
-301
lines changed

7 files changed

+373
-301
lines changed

src/DGCG.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def set_model_parameters(alpha, beta, time_samples, H_dimensions,
7373
operators.test_func = test_func
7474
operators.grad_test_func = grad_test_func
7575

76+
7677
def solve(data, **kwargs):
7778
"""Method to solve the given dynamic inverse problem for input data.
7879
@@ -148,9 +149,7 @@ def solve(data, **kwargs):
148149
# Set the parameters
149150
if not params['use_ffmpeg']:
150151
print("WARNING: ffmpeg disabled. Videos of animations cannot be saved")
151-
misc.use_ffmpeg = params['use_ffmpeg']
152-
else:
153-
misc.use_ffmpeg = True
152+
config.use_ffmpeg = params['use_ffmpeg']
154153
if params['insertion_max_restarts'] < params['insertion_min_restarts']:
155154
raise Exception("insertion_max_restarts < insertion_min_restarts." +
156155
"The execution is aborted")
@@ -202,21 +201,21 @@ def solve(data, **kwargs):
202201
return current_measure, (0, 'FAILURE: unable to reach a solution')
203202

204203

205-
206-
207204
def test_func_check(func):
208205
"""Tests if the dimensions of the given test function φ fit the model.
209206
"""
210207
# <+to_implement+>
211208
return True
212209

210+
213211
def test_grad_func_check(grad_func):
214212
"""Tests if the dimensions of the given test function gradient ∇φ fit.
215213
"""
216214
# <+to_implement+>
217215
return True
218216

219-
if __name__=='__main__':
217+
218+
if __name__ == ' __main__':
220219
pass
221220

222221

src/config.py

Lines changed: 120 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,121 @@
7272
declare that there are no available crossovers and then will propose a
7373
random curve for descent.
7474
crossover_child_F_threshold : numpy.float, default 0.8
75-
76-
77-
78-
79-
80-
Extensive description of each parameter of this module
81-
75+
Obtained crossover curves will be proposed for descensen only if their
76+
energy F(γ) is close to the best known stationary curve. How close it has
77+
to be is modulated by this parameter, it must satisfy
78+
F(crossover_child) < crossover_child_F_threshold * F(best_curve),
79+
remember that the energies are negative.
80+
crossover_max_distance: numpy.float, default 0.05
81+
Childs from two curves can be obtained only if at some point in time they
82+
get close one to another, this parameter indicates how close they need to
83+
get in H^1 norm for a crossover to happen.
84+
insertion_eps : numpy.float, defaylt 1e-10
85+
This is the tolenrance value to stop the algorithm. If the dual gap drops
86+
below it, the algorithm exits.
87+
insertion_max_restarts : int, default 20
88+
The maximum number of restarts of the multistart algorithm.
89+
insertion_min_restarts : int, default 15
90+
The minimum number of restarts of the multistart algorithm. This
91+
parameter is useful only in the case an early stop criteria is set
92+
via the `multistart_early_stop` parameter.
93+
multistart_inter_iteration_checkup : int, default 50
94+
While descending a single curve during the multistart gradient descent,
95+
the code will routinely check if curve being descended is close to the any
96+
element of the stationary point set. If so, the descense is stopped
97+
and the curve is discarded. This parameter regulates how often this
98+
check is done. Precaution: The algorithm also is coded to "omit" the curves
99+
that got too fast too close to the stationary point set. By "omiting", we
100+
mean that such a descented curve will not count towards the number of
101+
descented curves; "too fast" means that the curve got too close to the
102+
statonary set before the first checkup. A consequence of this is that if
103+
this checkup number is set too high, and there are a few stationary points,
104+
then (almost) all the descended curves will converge faster than the first
105+
checkup and as such, they will not count towards the number of attempted
106+
tries. Heavily slowing down the algorithm.
107+
multistart_max_discarded_tries : int, default 30
108+
If more than multistart_max_discarded_tries curves are discarded
109+
consecutively. Then the algorithm will issue a warning to set
110+
`multistart_inter_iteration_checkup` higher and will add a counter
111+
to the number of restarts. This is a failsafe against a `while true` loop.
112+
multistart_taboo_dist : numpy.float, default 0.01
113+
The distance, in H^1 norm, of a curve to an element of the stationary
114+
set to be discarded.
115+
multistart_energy_dist : numpy.float, default 0.01
116+
Acceleration parameter to measure the distance between the descended curve
117+
with those of the stationary set. The stationary point set is ordered by
118+
their F(γ) value, which is also readily available in a list. Therefore by
119+
computing the F(γ) value of the descended curve, one can just compare the
120+
current curve with those around that value, this parameter defines that
121+
radius.
122+
multistart_early_stop : lambda function, default constant equal to infinite
123+
This parameter allows to pass an early stop criteria to the multistart
124+
algorithm. The input is a two variable function whose first input is
125+
the number of attempted restarts, and the second parameter is the number
126+
of found stationary point. The multistart gradient descent will stop once
127+
it either reaches the `insertion_max_restart` value, or the value given by
128+
this function.
129+
multistart_proposition_max_iter : int, default 10000
130+
Each proposed curve must start with negative energy, if it does not, it
131+
is discarded and another curve is proposed. This parameter sets a limit on
132+
how many attempts will be done.
133+
multistart_descent_max_iter : int, default 16000
134+
This parameter limits the number of gradient descent steps that will be
135+
done on each descended curve.
136+
multistart_descent_soft_max_iter : int, default 5000
137+
This is a soft maximum number of iterations. If the currently descended
138+
curve has done more than this number of iterations, and simultaneously its
139+
energy is not "good enough", then the descense will be stopped.
140+
multistart_descent_soft_max_threshold : numpy.float, default 0.8
141+
Sets the threshold to discard the current descended curve, the current
142+
descended curve has to be at least this ratio closer to the best known
143+
stationary curve.
144+
multistart_descent_init_step : numpy.float, default 1
145+
The gradient descent uses an Armijo with backtracking descent. This
146+
parameter sets the intiial stepsize/
147+
multistart_descent_limit_stepsize : numpy.float, default 1e-20
148+
The gradient descent stops when the stepsize becomes smaller than this
149+
value.
150+
H1_tolerance : numpy.float, default 1e-5
151+
The quadratic optimization step will attempt to merge curves that are
152+
closer than this distance in H1 norm.
153+
curves_list_length_lim : int, default 1000
154+
The quadratic optimization step will take at most this number of stationary
155+
point found in the insertion step.
156+
curves_list_length_min : int, default 10,
157+
In the optimization step after the insertion step, the inserted curves are
158+
the union of the already known curves, together with those found in the
159+
multistart descent. This parameter sets least number of stationary curves
160+
from the mutlistart descent that have to be added for optimization.
161+
CVXOPT_TOL : numpy_float, default 1e-25
162+
CVXOPT is the used solver to tackle the quadratic optimization step. This
163+
parameter defines the considered tolerance value for both the relative and
164+
absolute errors.
165+
g_flow_opt_max_iter : int, default 100000
166+
During the sliding step, this parameter modules the maximum number of
167+
iterations to execute.
168+
g_flow_opt_in_between_iters : int, default 100
169+
During the sliding step, in between iterations, the weights of the measure
170+
are optomized via the optimization step. This parameter regulates how often
171+
this is done.
172+
g_flow_init_step : numpy.float, default 1
173+
The initial stepsize of the Armijo with Backtracking gradient descent
174+
for the Sliding step.
175+
g_flow_limit_stepsize : numpy.float, defaylt 1e-20
176+
During the sliding step, the descent stops once the stepsize reaches this
177+
size.
178+
log_output : boolean, default False
179+
Switch to log the convergence information into a .txt file into the
180+
`results` folder. WARNING: requires rework, too many useless lines are
181+
saved.
182+
save_output_each_N : int, default 1000
183+
How often the saved logs will be saved. This parameter consider the number
184+
of lines of the file.
185+
log_maximal_line_size : int, default 10000,
186+
Maximum size of the logfile. If exceeded, the file is discarded.
187+
use_ffmpeg : Boolean, default True
188+
Switch to use the ffmpeg library. This is required to save the obtained
189+
curves and measures as videos.
82190
"""
83191
# Standard imports
84192
import pickle
@@ -118,6 +226,7 @@ def self_pickle(filename):
118226
beta = 0.1
119227
# Problem data
120228
f_t = None
229+
multistart_max_discarded_tries = 30
121230

122231
# Measures parameters
123232
measure_coefficient_too_low = 1e-18
@@ -135,7 +244,7 @@ def self_pickle(filename):
135244
crossover_consecutive_inserts = 30
136245
crossover_search_attempts = 1000
137246
crossover_child_F_threshold = 0.8
138-
switching_max_distance = 0.05
247+
crossover_max_distance = 0.05
139248

140249
# Insertions step
141250
insertion_eps = 1e-10
@@ -144,11 +253,11 @@ def self_pickle(filename):
144253
insertion_max_restarts = 20
145254
insertion_min_restarts = 15
146255
multistart_inter_iteration_checkup = 50
256+
multistart_max_discarded_tries = 30
147257
multistart_taboo_dist = 0.01
148258
multistart_energy_dist = 0.01
149259
multistart_early_stop = lambda num_tries, num_found: np.inf
150260
multistart_proposition_max_iter = 10000
151-
multistart_max_discarded_tries = 30
152261

153262
# multistart gradient descent parameters
154263
multistart_descent_max_iter = 16000
@@ -174,59 +283,5 @@ def self_pickle(filename):
174283
save_output_each_N = 1000
175284
log_maximal_line_size = 10000
176285

177-
""" PARAMETER EXPLANATION GUIDE:
178-
179-
* Problem coefficients
180-
alpha, beta > 0, are the regularization parameters of the underlying problem.
181-
182-
* Curve and measures parameters
183-
curves_times_samples: the considered time discretization for the considered
184-
time-continuous curves in the time-continuous version of the problem
185-
measure_coefficient_too_low > 0, if a coefficient associated to some of the
186-
curves is too small, we consider the particular coefficient to be zero instead.
187-
188-
* Whole algorithm parameters
189-
full_max_iteration. A complete iteration consists of an insertion step,
190-
merging step and flowing step. This number limits the number of complete
191-
iterations of the algorithm.
192-
193-
* Max_curve parameters
194-
max_curve_x_res > 0 stands for the spatial resolution of the max_curve. The max
195-
curve is a curve that passes for each time through the maximum of the function
196-
w_t. Since afterwards the algorithm procedes to do a gradient descent, this
197-
maximum values can be chosen in a "less precise" way, therefore, instead of
198-
expensively finding the maximum at each step, a predefined spatial resolution
199-
is chosen and then the function w_t is discreetly sampled on a spatial grid
200-
with width defined by the max_curve_x_res parameter.
201-
202-
* Step3 tabu search iteration parameters
203-
- step3_min_attempts_to_find_better_curve,
204-
- step3_max_attempts_to_find_better_curve
205-
At the step3, we need to find a curve that minimizes the target step3_energy.
206-
The problem is smooth but not convex. Therefore, the proposed approach is to
207-
shoot some curves and then descend them. By doing so, we are able to find local
208-
minima of the target functional. Empirically, it seems that it is not required
209-
to have the precise minimum of the functional, so these parameters basically
210-
allow to accelerate the algorithm trade-offing some sloppyness.
211-
step3_min_attempts_to_find_better_curve stands for the minimum number of
212-
attempts taken by the algorithm to find an acceptable curve to insert.
213-
If the algorithm does not find an acceptable curve to insert after this minimum
214-
number of tries, it will keep trying to find better candidates until reaching
215-
step3_max_attempts_to_find_better_curve. If this number is reached and no
216-
acceptable curve was found, the algorithm considers the true minimum to be
217-
already visited, and therefore the algorithm stops.
218-
- step3_tabu_in_between_iteration_condition_checkup
219-
- step3_tabu_dist
220-
The tabu search has an optimization step in which no all curves are descended
221-
to the fullest, as it is clear that they are descending to an already known
222-
local minimum. To do it so, the H1 norm is evaluated from the current curve
223-
candidate and those in the tabu set, the threshold in which to decide that the
224-
curve will descent to any already known local minimum curve is step3_tabu_dist.
225-
step3_tabu_in_between_iteration_condition_checkup is a parameter indicating
226-
after how many iterations to check if the current curve is close to someone
227-
on the Tabu set. (a low value implies a lot of wasted resources checking
228-
against all the curves in the Tabu set, a high value implies wasting too much
229-
resources descending a curve that clearly is converging to one in the tabu
230-
set).
231-
232-
"""
286+
# Miscelaneous
287+
use_ffmpeg = True

src/curves.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ def add(self, new_curve, new_intensity):
233233
def __add__(self, measure2):
234234
new_measure = copy.deepcopy(self)
235235
new_measure.curves.extend(copy.deepcopy(measure2.curves))
236-
new_measure.energies = np.append(new_measure.energies, measure2.energies)
236+
new_measure.energies = np.append(new_measure.energies,
237+
measure2.energies)
237238
new_measure.intensities = np.append(new_measure.intensities,
238239
measure2.intensities)
239240
new_measure.main_energy = None

src/insertion_mod.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ordered_list_of_lists:
2727
# appending in a sorted manner.
2828
def __init__(self):
2929
self.data = []
30+
3031
def add_empty_element_in_index(self, i):
3132
# Insert an empty list of lists in the desired location
3233
num_after_elements = len(self.data) - i
@@ -35,9 +36,11 @@ def add_empty_element_in_index(self, i):
3536
# Update all the past lists
3637
for j in range(i):
3738
self.data[j].insert(i-j-1, [])
39+
3840
def GET(self, i, j):
3941
# Find the information hold for the pair i,j, with i < j
4042
return self.data[i][j-i-1]
43+
4144
def POST(self, i, j, val):
4245
# Insert information in target location
4346
self.data[i][j-i-1] = val
@@ -185,7 +188,7 @@ def rejection_sampling(t, w_t):
185188
else:
186189
# reject
187190
iter_index = iter_index+1
188-
sys.exit(('The rejection_sampling algorithm failed to find sample in {} '+
191+
sys.exit(('The rejection_sampling algorithm failed to find sample in {} ' +
189192
'iterations').format(iter_index))
190193

191194
def curve_smoother(curve):
@@ -201,13 +204,13 @@ def curve_smoother(curve):
201204
return curves.curve(curve.t, new_points)
202205

203206
def switch_at(curve1, curve2, idx):
204-
# Method that given a particular time index, produces the two curves obtained
205-
# by switching at that position
207+
# Method that given a particular time index, produces the two curves
208+
# obtained by switching at that position
206209
intermediate_loc = (curve1.x[idx] + curve2.x[idx]).reshape(1, -1)/2
207210
tail_x1 = curve1.x[:idx, :]
208211
tail_x2 = curve2.x[:idx, :]
209212
head_x1 = curve1.x[idx+1:, :]
210-
head_x2 = curve2.x[idx+1:, :]
213+
head_x2 = curve2.x[idx+1:, :]
211214
new_x1 = np.vstack((tail_x1, intermediate_loc, head_x2))
212215
new_x2 = np.vstack((tail_x2, intermediate_loc, head_x1))
213216
new_curve1 = curves.curve(curve1.t, new_x1)
@@ -223,14 +226,14 @@ def crossover(curve1, curve2):
223226
# Then recognize the jumps: 1 if they were apart and got close
224227
# -1 if they were close and got far apart
225228
# 0 if nothing happened
226-
jumps = np.diff((norms <= config.switching_max_distance).astype(int))
229+
jumps = np.diff((norms <= config.crossover_max_distance).astype(int))
227230
if len(jumps) == 0:
228231
# if there are no jumps, do not return
229232
return []
230233
# We want the indexes with 1s
231234
jump_idx = np.where(jumps == 1)[0] + 1
232235
# And we need to discard the last one if they stayed close until the end
233-
if norms[-1] <= config.switching_max_distance:
236+
if norms[-1] <= config.crossover_max_distance:
234237
jump_idx = jump_idx[:-1]
235238
# We have the index locations for the switchings
236239
curve_descendants = []

src/insertion_step.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def insertion_step(current_measure):
4343
insertion_eps = config.insertion_eps
4444
if dual_gap < 0:
4545
print('Somehow dual gap negative, something must be wrong')
46-
import code; code.interact(local=dict(globals(), **locals()))
46+
print('Likely the TOL value is too small these are rounding errors')
4747
if dual_gap < insertion_eps:
4848
logger.status([1, 2, 4])
4949
exit_flag = 0 # the algorithm stops
@@ -135,10 +135,10 @@ def multistart_descent(current_measure):
135135
#
136136
while descent_iters < descent_max_iter and stepsize > lim_stepsize:
137137
# This while-loop applies the gradient descent on curves,
138-
# while simultaneously it checks in intermediates steps if
138+
# while simultaneously it checks in intermediates steps if
139139
# certain conditions are satisfied. These are the possible cases:
140140
# case 1: A stationary point is found. This is captured when the
141-
# stepsize goes below lim_stepsize.
141+
# stepsize goes below lim_stepsize.
142142
# case 2: The descended curve got at some point close to the
143143
# stationary set. The while breaks.
144144
# case 2.2: If this curve gets too close before the first check,
@@ -147,7 +147,8 @@ def multistart_descent(current_measure):
147147
# while not getting close enough to the taboo set.
148148
# (this is if descent_soft_max_iter is reached)
149149
# case 3.1: If the value F(γ) is 0.9 close to the best known case,
150-
# the descent continuous up to descent_max_iter is reached.
150+
# the descent continuous up to descent_max_iter is
151+
# reached.
151152
# case 3.2: If the value F(γ) is not close enought to the best
152153
# known case, the while loop is ended.
153154
close_to_known_set = False

0 commit comments

Comments
 (0)