The idea of the algorithm is to find where the next bend is going to be, and restart from there. Knowing the lastprevious bend, we maintain the minimum and maximum slope for the next line, and which $i$ is at the limit, until we are forced to introduce a new bend.
def find_next_bend(n, l, u, x, last_bendprevious_bend):
min_slope = -float("inf")
max_slope = float("inf")
min_slope_ind = -1
max_slope_ind = -1
for i in range(last_bend+1, n):
new_min_slope = (l[i] - x[last_bend]x[previous_bend]) / (i-last_bendprevious_bend)
new_max_slope = (u[i] - x[last_bend]x[previous_bend]) / (i-last_bendprevious_bend)
if new_min_slope > max_slope:
# Bend upwards
x[max_slope_ind] = u[max_slope_ind]
return max_slope_ind
if new_max_slope < min_slope:
# Bend downwards
x[min_slope_ind] = l[min_slope_ind]
return min_slope_ind
if new_max_slope < max_slope:
# Restrict max possible slope
max_slope_ind = i
max_slope = new_max_slope
if new_min_slope > min_slope:
# Restrict min possible slope
min_slope_ind = i
min_slope = new_min_slope
There are cornercases for the first and last breakpointbend, that I won't describe here: they are commented in the full code. The proof of the algorithm is left as an exercise for the reader :)